@cyclonedx/cdxgen 12.3.2 → 12.3.3

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 (53) hide show
  1. package/README.md +6 -0
  2. package/data/rules/ci-permissions.yaml +132 -0
  3. package/data/rules/dependency-sources.yaml +65 -5
  4. package/data/rules/package-integrity.yaml +22 -0
  5. package/lib/cli/index.js +141 -39
  6. package/lib/cli/index.poku.js +579 -1
  7. package/lib/helpers/agentFormulationParser.js +6 -2
  8. package/lib/helpers/agentFormulationParser.poku.js +42 -0
  9. package/lib/helpers/analyzer.js +38 -9
  10. package/lib/helpers/analyzer.poku.js +67 -0
  11. package/lib/helpers/chromextutils.js +25 -3
  12. package/lib/helpers/chromextutils.poku.js +68 -0
  13. package/lib/helpers/ciParsers/githubActions.js +79 -0
  14. package/lib/helpers/ciParsers/githubActions.poku.js +103 -0
  15. package/lib/helpers/communityAiConfigParser.js +15 -5
  16. package/lib/helpers/communityAiConfigParser.poku.js +71 -0
  17. package/lib/helpers/depsUtils.js +5 -0
  18. package/lib/helpers/depsUtils.poku.js +55 -0
  19. package/lib/helpers/display.js +45 -22
  20. package/lib/helpers/display.poku.js +47 -60
  21. package/lib/helpers/mcpConfigParser.js +21 -5
  22. package/lib/helpers/mcpConfigParser.poku.js +39 -2
  23. package/lib/helpers/propertySanitizer.js +121 -0
  24. package/lib/helpers/utils.js +951 -40
  25. package/lib/helpers/utils.poku.js +882 -0
  26. package/lib/managers/binary.js +16 -0
  27. package/lib/managers/binary.poku.js +1 -0
  28. package/lib/managers/docker.js +240 -16
  29. package/lib/managers/docker.poku.js +1142 -2
  30. package/lib/server/server.js +7 -4
  31. package/lib/server/server.poku.js +36 -1
  32. package/lib/stages/postgen/auditBom.poku.js +644 -2
  33. package/package.json +2 -1
  34. package/types/lib/cli/index.d.ts.map +1 -1
  35. package/types/lib/helpers/agentFormulationParser.d.ts.map +1 -1
  36. package/types/lib/helpers/analyzer.d.ts.map +1 -1
  37. package/types/lib/helpers/chromextutils.d.ts.map +1 -1
  38. package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -1
  39. package/types/lib/helpers/communityAiConfigParser.d.ts.map +1 -1
  40. package/types/lib/helpers/depsUtils.d.ts.map +1 -1
  41. package/types/lib/helpers/display.d.ts +1 -0
  42. package/types/lib/helpers/display.d.ts.map +1 -1
  43. package/types/lib/helpers/mcpConfigParser.d.ts +1 -1
  44. package/types/lib/helpers/mcpConfigParser.d.ts.map +1 -1
  45. package/types/lib/helpers/propertySanitizer.d.ts +3 -0
  46. package/types/lib/helpers/propertySanitizer.d.ts.map +1 -0
  47. package/types/lib/helpers/utils.d.ts +29 -0
  48. package/types/lib/helpers/utils.d.ts.map +1 -1
  49. package/types/lib/managers/binary.d.ts.map +1 -1
  50. package/types/lib/managers/docker.d.ts +3 -0
  51. package/types/lib/managers/docker.d.ts.map +1 -1
  52. package/types/lib/server/server.d.ts +1 -0
  53. package/types/lib/server/server.d.ts.map +1 -1
@@ -190,7 +190,7 @@ describe("evaluateRule", () => {
190
190
  );
191
191
  });
192
192
 
193
- it("should detect npm install script from non-registry source (PKG-001)", async () => {
193
+ it("should detect npm install script from direct manifest source (PKG-001)", async () => {
194
194
  const rules = await loadRules(RULES_DIR);
195
195
  const rule = rules.find((r) => r.id === "PKG-001");
196
196
  assert.ok(rule, "PKG-001 rule should exist");
@@ -198,7 +198,11 @@ describe("evaluateRule", () => {
198
198
  const bom = makeBom([
199
199
  makeComponent("sketchy-pkg", "1.0.0", [
200
200
  ["cdx:npm:hasInstallScript", "true"],
201
- ["cdx:npm:isRegistryDependency", "false"],
201
+ ["cdx:npm:manifestSourceType", "git"],
202
+ [
203
+ "cdx:npm:manifestSource",
204
+ "git+https://github.com/acme/sketchy-pkg.git",
205
+ ],
202
206
  ]),
203
207
  ]);
204
208
 
@@ -207,6 +211,122 @@ describe("evaluateRule", () => {
207
211
  assert.strictEqual(findings[0].severity, "high");
208
212
  });
209
213
 
214
+ it("should detect npm install scripts from url and path manifest sources for PKG-001", async () => {
215
+ const rules = await loadRules(RULES_DIR);
216
+ const rule = rules.find((r) => r.id === "PKG-001");
217
+ assert.ok(rule, "PKG-001 rule should exist");
218
+
219
+ for (const manifestSourceType of ["url", "path"]) {
220
+ const bom = makeBom([
221
+ makeComponent(`sketchy-${manifestSourceType}`, "1.0.0", [
222
+ ["cdx:npm:hasInstallScript", "true"],
223
+ ["cdx:npm:manifestSourceType", manifestSourceType],
224
+ ["cdx:npm:manifestSource", `${manifestSourceType}:example`],
225
+ ]),
226
+ ]);
227
+
228
+ const findings = await evaluateRule(rule, bom);
229
+ assert.ok(findings.length > 0);
230
+ }
231
+ });
232
+
233
+ it("should not detect npm install script without manifest source evidence for PKG-001", async () => {
234
+ const rules = await loadRules(RULES_DIR);
235
+ const rule = rules.find((r) => r.id === "PKG-001");
236
+ assert.ok(rule, "PKG-001 rule should exist");
237
+
238
+ const bom = makeBom([
239
+ makeComponent("registry-pkg", "1.0.0", [
240
+ ["cdx:npm:hasInstallScript", "true"],
241
+ ["cdx:npm:isRegistryDependency", "false"],
242
+ ]),
243
+ ]);
244
+
245
+ const findings = await evaluateRule(rule, bom);
246
+ assert.strictEqual(findings.length, 0);
247
+ });
248
+
249
+ it("should detect Collider packages from insecure HTTP origins (PKG-009)", async () => {
250
+ const rules = await loadRules(RULES_DIR);
251
+ const rule = rules.find((r) => r.id === "PKG-009");
252
+ assert.ok(rule, "PKG-009 rule should exist");
253
+
254
+ const bom = makeBom([
255
+ makeComponent("fmt", "11.0.2", [
256
+ ["cdx:collider:dependencyKind", "direct"],
257
+ ["cdx:collider:origin", "http://mirror.example.com/collider/v2/"],
258
+ ["cdx:collider:originScheme", "http"],
259
+ ["cdx:collider:originHost", "mirror.example.com"],
260
+ ]),
261
+ ]);
262
+
263
+ const findings = await evaluateRule(rule, bom);
264
+ assert.ok(findings.length > 0, "Should detect insecure Collider origin");
265
+ assert.strictEqual(findings[0].ruleId, "PKG-009");
266
+ assert.strictEqual(findings[0].severity, "medium");
267
+ });
268
+
269
+ it("should detect Collider origins that required sanitization (PKG-010)", async () => {
270
+ const rules = await loadRules(RULES_DIR);
271
+ const rule = rules.find((r) => r.id === "PKG-010");
272
+ assert.ok(rule, "PKG-010 rule should exist");
273
+
274
+ const bom = makeBom([
275
+ makeComponent("spdlog", "1.15.0", [
276
+ ["cdx:collider:dependencyKind", "direct"],
277
+ ["cdx:collider:origin", "https://example.com/collider/v2/"],
278
+ ["cdx:collider:originScheme", "https"],
279
+ ["cdx:collider:originSanitized", "true"],
280
+ ]),
281
+ ]);
282
+
283
+ const findings = await evaluateRule(rule, bom);
284
+ assert.ok(findings.length > 0, "Should detect sanitized Collider origin");
285
+ assert.strictEqual(findings[0].ruleId, "PKG-010");
286
+ assert.strictEqual(findings[0].severity, "low");
287
+ });
288
+
289
+ it("should detect python dependency from direct manifest source (PKG-011)", async () => {
290
+ const rules = await loadRules(RULES_DIR);
291
+ const rule = rules.find((r) => r.id === "PKG-011");
292
+ assert.ok(rule, "PKG-011 rule should exist");
293
+
294
+ const bom = makeBom([
295
+ makeComponent("suspicious-python-pkg", "1.0.0", [
296
+ ["cdx:pypi:manifestSourceType", "url"],
297
+ [
298
+ "cdx:pypi:manifestSource",
299
+ "https://example.com/suspicious-python-pkg.whl",
300
+ ],
301
+ ]),
302
+ ]);
303
+
304
+ const findings = await evaluateRule(rule, bom);
305
+ assert.ok(findings.length > 0, "Should detect python direct source risk");
306
+ assert.strictEqual(findings[0].ruleId, "PKG-011");
307
+ assert.strictEqual(findings[0].severity, "high");
308
+ });
309
+
310
+ it("should detect Collider packages missing valid wrap hashes (INT-014)", async () => {
311
+ const rules = await loadRules(RULES_DIR);
312
+ const rule = rules.find((r) => r.id === "INT-014");
313
+ assert.ok(rule, "INT-014 rule should exist");
314
+
315
+ const bom = makeBom([
316
+ makeComponent("fast_float", "8.0.2", [
317
+ ["cdx:collider:dependencyKind", "transitive"],
318
+ ["cdx:collider:hasWrapHash", "false"],
319
+ ["cdx:collider:wrapHash", "not-a-sha256"],
320
+ ["cdx:collider:wrapHashInvalid", "true"],
321
+ ]),
322
+ ]);
323
+
324
+ const findings = await evaluateRule(rule, bom);
325
+ assert.ok(findings.length > 0, "Should detect missing Collider wrap hash");
326
+ assert.strictEqual(findings[0].ruleId, "INT-014");
327
+ assert.strictEqual(findings[0].severity, "high");
328
+ });
329
+
210
330
  it("should detect OIDC token issuance to a non-official action (CI-002)", async () => {
211
331
  const rules = await loadRules(RULES_DIR);
212
332
  const rule = rules.find((r) => r.id === "CI-002");
@@ -1434,6 +1554,528 @@ describe("evaluateRule", () => {
1434
1554
  assert.match(findings[0].message, /Heuristic review/);
1435
1555
  });
1436
1556
 
1557
+ it("should detect disabled npm cache when npm distributions are resolved remotely (CI-022)", async () => {
1558
+ const rules = await loadRules(RULES_DIR);
1559
+ const rule = rules.find((r) => r.id === "CI-022");
1560
+ assert.ok(rule, "CI-022 rule should exist");
1561
+
1562
+ const bom = makeBom(
1563
+ [
1564
+ {
1565
+ type: "library",
1566
+ name: "left-pad",
1567
+ version: "1.3.0",
1568
+ purl: "pkg:npm/left-pad@1.3.0",
1569
+ "bom-ref": "pkg:npm/left-pad@1.3.0",
1570
+ externalReferences: [
1571
+ {
1572
+ type: "distribution",
1573
+ url: "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
1574
+ },
1575
+ ],
1576
+ properties: [
1577
+ {
1578
+ name: "cdx:npm:manifestSourceType",
1579
+ value: "url",
1580
+ },
1581
+ {
1582
+ name: "cdx:npm:manifestSource",
1583
+ value: "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
1584
+ },
1585
+ ],
1586
+ },
1587
+ ],
1588
+ [],
1589
+ [
1590
+ {
1591
+ type: "application",
1592
+ name: "setup-node",
1593
+ version: "v4",
1594
+ purl: "pkg:github/actions/setup-node@v4",
1595
+ "bom-ref": "pkg:github/actions/setup-node@v4",
1596
+ properties: [
1597
+ {
1598
+ name: "cdx:github:action:uses",
1599
+ value: "actions/setup-node@v4",
1600
+ },
1601
+ { name: "cdx:github:action:disablesBuildCache", value: "true" },
1602
+ { name: "cdx:github:action:buildCacheEcosystem", value: "npm" },
1603
+ {
1604
+ name: "cdx:github:action:buildCacheDisableInput",
1605
+ value: "package-manager-cache",
1606
+ },
1607
+ {
1608
+ name: "cdx:github:action:buildCacheDisableValue",
1609
+ value: "false",
1610
+ },
1611
+ {
1612
+ name: "cdx:github:workflow:file",
1613
+ value: ".github/workflows/ci.yml",
1614
+ },
1615
+ ],
1616
+ },
1617
+ ],
1618
+ );
1619
+
1620
+ const findings = await evaluateRule(rule, bom);
1621
+ assert.ok(findings.length > 0, "Should detect disabled npm cache");
1622
+ assert.strictEqual(findings[0].severity, "medium");
1623
+ });
1624
+
1625
+ it("should detect disabled npm cache for git manifest sources (CI-022)", async () => {
1626
+ const rules = await loadRules(RULES_DIR);
1627
+ const rule = rules.find((r) => r.id === "CI-022");
1628
+ assert.ok(rule, "CI-022 rule should exist");
1629
+
1630
+ const bom = makeBom(
1631
+ [
1632
+ {
1633
+ type: "library",
1634
+ name: "git-dep",
1635
+ version: "2.0.0",
1636
+ purl: "pkg:npm/git-dep@2.0.0",
1637
+ "bom-ref": "pkg:npm/git-dep@2.0.0",
1638
+ externalReferences: [
1639
+ {
1640
+ type: "distribution",
1641
+ url: "git+https://github.com/acme/git-dep.git",
1642
+ },
1643
+ ],
1644
+ properties: [
1645
+ {
1646
+ name: "cdx:npm:manifestSourceType",
1647
+ value: "git",
1648
+ },
1649
+ {
1650
+ name: "cdx:npm:manifestSource",
1651
+ value: "git+https://github.com/acme/git-dep.git",
1652
+ },
1653
+ ],
1654
+ },
1655
+ ],
1656
+ [],
1657
+ [
1658
+ {
1659
+ type: "application",
1660
+ name: "setup-node",
1661
+ version: "v4",
1662
+ purl: "pkg:github/actions/setup-node@v4",
1663
+ "bom-ref": "pkg:github/actions/setup-node@v4",
1664
+ properties: [
1665
+ {
1666
+ name: "cdx:github:action:uses",
1667
+ value: "actions/setup-node@v4",
1668
+ },
1669
+ { name: "cdx:github:action:disablesBuildCache", value: "true" },
1670
+ { name: "cdx:github:action:buildCacheEcosystem", value: "npm" },
1671
+ ],
1672
+ },
1673
+ ],
1674
+ );
1675
+
1676
+ const findings = await evaluateRule(rule, bom);
1677
+ assert.ok(findings.length > 0, "Should detect disabled npm cache");
1678
+ });
1679
+
1680
+ it("should not detect disabled npm cache for registry-only npm dependencies (CI-022)", async () => {
1681
+ const rules = await loadRules(RULES_DIR);
1682
+ const rule = rules.find((r) => r.id === "CI-022");
1683
+ assert.ok(rule, "CI-022 rule should exist");
1684
+
1685
+ const bom = makeBom(
1686
+ [
1687
+ {
1688
+ type: "library",
1689
+ name: "left-pad",
1690
+ version: "1.3.0",
1691
+ purl: "pkg:npm/left-pad@1.3.0",
1692
+ "bom-ref": "pkg:npm/left-pad@1.3.0",
1693
+ externalReferences: [
1694
+ {
1695
+ type: "distribution",
1696
+ url: "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
1697
+ },
1698
+ ],
1699
+ },
1700
+ ],
1701
+ [],
1702
+ [
1703
+ {
1704
+ type: "application",
1705
+ name: "setup-node",
1706
+ version: "v4",
1707
+ purl: "pkg:github/actions/setup-node@v4",
1708
+ "bom-ref": "pkg:github/actions/setup-node@v4",
1709
+ properties: [
1710
+ {
1711
+ name: "cdx:github:action:uses",
1712
+ value: "actions/setup-node@v4",
1713
+ },
1714
+ { name: "cdx:github:action:disablesBuildCache", value: "true" },
1715
+ { name: "cdx:github:action:buildCacheEcosystem", value: "npm" },
1716
+ ],
1717
+ },
1718
+ ],
1719
+ );
1720
+
1721
+ const findings = await evaluateRule(rule, bom);
1722
+ assert.strictEqual(findings.length, 0);
1723
+ });
1724
+
1725
+ it("should not detect disabled npm cache for local path manifest sources (CI-022)", async () => {
1726
+ const rules = await loadRules(RULES_DIR);
1727
+ const rule = rules.find((r) => r.id === "CI-022");
1728
+ assert.ok(rule, "CI-022 rule should exist");
1729
+
1730
+ const bom = makeBom(
1731
+ [
1732
+ {
1733
+ type: "library",
1734
+ name: "local-dep",
1735
+ version: "1.0.0",
1736
+ purl: "pkg:npm/local-dep@1.0.0",
1737
+ "bom-ref": "pkg:npm/local-dep@1.0.0",
1738
+ externalReferences: [
1739
+ {
1740
+ type: "distribution",
1741
+ url: "file:../libs/local-dep",
1742
+ },
1743
+ ],
1744
+ properties: [
1745
+ {
1746
+ name: "cdx:npm:manifestSourceType",
1747
+ value: "path",
1748
+ },
1749
+ {
1750
+ name: "cdx:npm:manifestSource",
1751
+ value: "file:../libs/local-dep",
1752
+ },
1753
+ ],
1754
+ },
1755
+ ],
1756
+ [],
1757
+ [
1758
+ {
1759
+ type: "application",
1760
+ name: "setup-node",
1761
+ version: "v4",
1762
+ purl: "pkg:github/actions/setup-node@v4",
1763
+ "bom-ref": "pkg:github/actions/setup-node@v4",
1764
+ properties: [
1765
+ {
1766
+ name: "cdx:github:action:uses",
1767
+ value: "actions/setup-node@v4",
1768
+ },
1769
+ { name: "cdx:github:action:disablesBuildCache", value: "true" },
1770
+ { name: "cdx:github:action:buildCacheEcosystem", value: "npm" },
1771
+ ],
1772
+ },
1773
+ ],
1774
+ );
1775
+
1776
+ const findings = await evaluateRule(rule, bom);
1777
+ assert.strictEqual(findings.length, 0);
1778
+ });
1779
+
1780
+ it("should detect disabled Python cache when pylock sources use remote artifacts (CI-023)", async () => {
1781
+ const rules = await loadRules(RULES_DIR);
1782
+ const rule = rules.find((r) => r.id === "CI-023");
1783
+ assert.ok(rule, "CI-023 rule should exist");
1784
+
1785
+ const bom = makeBom(
1786
+ [
1787
+ {
1788
+ type: "library",
1789
+ name: "requests",
1790
+ version: "2.32.0",
1791
+ purl: "pkg:pypi/requests@2.32.0",
1792
+ "bom-ref": "pkg:pypi/requests@2.32.0",
1793
+ properties: [
1794
+ {
1795
+ name: "cdx:pypi:manifestSourceType",
1796
+ value: "url",
1797
+ },
1798
+ {
1799
+ name: "cdx:pypi:manifestSource",
1800
+ value:
1801
+ "https://files.pythonhosted.org/packages/requests-2.32.0.tar.gz",
1802
+ },
1803
+ ],
1804
+ },
1805
+ ],
1806
+ [],
1807
+ [
1808
+ {
1809
+ type: "application",
1810
+ name: "setup-python",
1811
+ version: "v5",
1812
+ purl: "pkg:github/actions/setup-python@v5",
1813
+ "bom-ref": "pkg:github/actions/setup-python@v5",
1814
+ properties: [
1815
+ {
1816
+ name: "cdx:github:action:uses",
1817
+ value: "actions/setup-python@v5",
1818
+ },
1819
+ { name: "cdx:github:action:disablesBuildCache", value: "true" },
1820
+ { name: "cdx:github:action:buildCacheEcosystem", value: "pypi" },
1821
+ {
1822
+ name: "cdx:github:action:buildCacheDisableInput",
1823
+ value: "cache",
1824
+ },
1825
+ {
1826
+ name: "cdx:github:action:buildCacheDisableValue",
1827
+ value: "false",
1828
+ },
1829
+ {
1830
+ name: "cdx:github:workflow:file",
1831
+ value: ".github/workflows/ci.yml",
1832
+ },
1833
+ ],
1834
+ },
1835
+ ],
1836
+ );
1837
+
1838
+ const findings = await evaluateRule(rule, bom);
1839
+ assert.ok(findings.length > 0, "Should detect disabled Python cache");
1840
+ assert.strictEqual(findings[0].severity, "medium");
1841
+ });
1842
+
1843
+ it("should detect disabled Python cache for git manifest sources (CI-023)", async () => {
1844
+ const rules = await loadRules(RULES_DIR);
1845
+ const rule = rules.find((r) => r.id === "CI-023");
1846
+ assert.ok(rule, "CI-023 rule should exist");
1847
+
1848
+ const bom = makeBom(
1849
+ [
1850
+ {
1851
+ type: "library",
1852
+ name: "private-lib",
1853
+ version: "1.0.0",
1854
+ purl: "pkg:pypi/private-lib@1.0.0",
1855
+ "bom-ref": "pkg:pypi/private-lib@1.0.0",
1856
+ properties: [
1857
+ {
1858
+ name: "cdx:pypi:manifestSourceType",
1859
+ value: "git",
1860
+ },
1861
+ {
1862
+ name: "cdx:pypi:manifestSource",
1863
+ value: "git+https://github.com/acme/private-lib.git",
1864
+ },
1865
+ ],
1866
+ },
1867
+ ],
1868
+ [],
1869
+ [
1870
+ {
1871
+ type: "application",
1872
+ name: "setup-python",
1873
+ version: "v5",
1874
+ purl: "pkg:github/actions/setup-python@v5",
1875
+ "bom-ref": "pkg:github/actions/setup-python@v5",
1876
+ properties: [
1877
+ {
1878
+ name: "cdx:github:action:uses",
1879
+ value: "actions/setup-python@v5",
1880
+ },
1881
+ { name: "cdx:github:action:disablesBuildCache", value: "true" },
1882
+ { name: "cdx:github:action:buildCacheEcosystem", value: "pypi" },
1883
+ ],
1884
+ },
1885
+ ],
1886
+ );
1887
+
1888
+ const findings = await evaluateRule(rule, bom);
1889
+ assert.ok(findings.length > 0, "Should detect disabled Python cache");
1890
+ });
1891
+
1892
+ it("should not detect disabled Python cache for registry-only lockfile sources (CI-023)", async () => {
1893
+ const rules = await loadRules(RULES_DIR);
1894
+ const rule = rules.find((r) => r.id === "CI-023");
1895
+ assert.ok(rule, "CI-023 rule should exist");
1896
+
1897
+ const bom = makeBom(
1898
+ [
1899
+ {
1900
+ type: "library",
1901
+ name: "requests",
1902
+ version: "2.32.0",
1903
+ purl: "pkg:pypi/requests@2.32.0",
1904
+ "bom-ref": "pkg:pypi/requests@2.32.0",
1905
+ properties: [
1906
+ {
1907
+ name: "cdx:pylock:archive",
1908
+ value:
1909
+ '{"url":"https://files.pythonhosted.org/packages/requests-2.32.0.tar.gz"}',
1910
+ },
1911
+ ],
1912
+ },
1913
+ ],
1914
+ [],
1915
+ [
1916
+ {
1917
+ type: "application",
1918
+ name: "setup-python",
1919
+ version: "v5",
1920
+ purl: "pkg:github/actions/setup-python@v5",
1921
+ "bom-ref": "pkg:github/actions/setup-python@v5",
1922
+ properties: [
1923
+ {
1924
+ name: "cdx:github:action:uses",
1925
+ value: "actions/setup-python@v5",
1926
+ },
1927
+ { name: "cdx:github:action:disablesBuildCache", value: "true" },
1928
+ { name: "cdx:github:action:buildCacheEcosystem", value: "pypi" },
1929
+ ],
1930
+ },
1931
+ ],
1932
+ );
1933
+
1934
+ const findings = await evaluateRule(rule, bom);
1935
+ assert.strictEqual(findings.length, 0);
1936
+ });
1937
+
1938
+ it("should not detect disabled Python cache for local path manifest sources (CI-023)", async () => {
1939
+ const rules = await loadRules(RULES_DIR);
1940
+ const rule = rules.find((r) => r.id === "CI-023");
1941
+ assert.ok(rule, "CI-023 rule should exist");
1942
+
1943
+ const bom = makeBom(
1944
+ [
1945
+ {
1946
+ type: "library",
1947
+ name: "local-lib",
1948
+ version: "1.0.0",
1949
+ purl: "pkg:pypi/local-lib@1.0.0",
1950
+ "bom-ref": "pkg:pypi/local-lib@1.0.0",
1951
+ properties: [
1952
+ {
1953
+ name: "cdx:pypi:manifestSourceType",
1954
+ value: "path",
1955
+ },
1956
+ {
1957
+ name: "cdx:pypi:manifestSource",
1958
+ value: "../libs/local-lib",
1959
+ },
1960
+ ],
1961
+ },
1962
+ ],
1963
+ [],
1964
+ [
1965
+ {
1966
+ type: "application",
1967
+ name: "setup-python",
1968
+ version: "v5",
1969
+ purl: "pkg:github/actions/setup-python@v5",
1970
+ "bom-ref": "pkg:github/actions/setup-python@v5",
1971
+ properties: [
1972
+ {
1973
+ name: "cdx:github:action:uses",
1974
+ value: "actions/setup-python@v5",
1975
+ },
1976
+ { name: "cdx:github:action:disablesBuildCache", value: "true" },
1977
+ { name: "cdx:github:action:buildCacheEcosystem", value: "pypi" },
1978
+ ],
1979
+ },
1980
+ ],
1981
+ );
1982
+
1983
+ const findings = await evaluateRule(rule, bom);
1984
+ assert.strictEqual(findings.length, 0);
1985
+ });
1986
+
1987
+ it("should detect disabled Cargo cache for git manifest sources (CI-024)", async () => {
1988
+ const rules = await loadRules(RULES_DIR);
1989
+ const rule = rules.find((r) => r.id === "CI-024");
1990
+ assert.ok(rule, "CI-024 rule should exist");
1991
+
1992
+ const bom = makeBom(
1993
+ [
1994
+ {
1995
+ type: "library",
1996
+ name: "git-crate",
1997
+ version: "git+https://github.com/acme/git-crate.git",
1998
+ purl: "pkg:cargo/git-crate@git+https://github.com/acme/git-crate.git",
1999
+ "bom-ref":
2000
+ "pkg:cargo/git-crate@git+https://github.com/acme/git-crate.git",
2001
+ properties: [
2002
+ {
2003
+ name: "cdx:cargo:git",
2004
+ value: "https://github.com/acme/git-crate.git",
2005
+ },
2006
+ ],
2007
+ },
2008
+ ],
2009
+ [],
2010
+ [
2011
+ {
2012
+ type: "application",
2013
+ name: "setup-rust",
2014
+ version: "v1",
2015
+ purl: "pkg:github/moonrepo/setup-rust@v1",
2016
+ "bom-ref": "pkg:github/moonrepo/setup-rust@v1",
2017
+ properties: [
2018
+ {
2019
+ name: "cdx:github:action:uses",
2020
+ value: "moonrepo/setup-rust@v1",
2021
+ },
2022
+ { name: "cdx:github:action:disablesBuildCache", value: "true" },
2023
+ { name: "cdx:github:action:buildCacheEcosystem", value: "cargo" },
2024
+ ],
2025
+ },
2026
+ ],
2027
+ );
2028
+
2029
+ const findings = await evaluateRule(rule, bom);
2030
+ assert.ok(findings.length > 0, "Should detect disabled Cargo cache");
2031
+ assert.strictEqual(findings[0].severity, "medium");
2032
+ });
2033
+
2034
+ it("should not detect disabled Cargo cache for local path manifest sources (CI-024)", async () => {
2035
+ const rules = await loadRules(RULES_DIR);
2036
+ const rule = rules.find((r) => r.id === "CI-024");
2037
+ assert.ok(rule, "CI-024 rule should exist");
2038
+
2039
+ const bom = makeBom(
2040
+ [
2041
+ {
2042
+ type: "library",
2043
+ name: "path-crate",
2044
+ version: "path+../path-crate",
2045
+ purl: "pkg:cargo/path-crate@path+../path-crate",
2046
+ "bom-ref": "pkg:cargo/path-crate@path+../path-crate",
2047
+ properties: [
2048
+ {
2049
+ name: "cdx:cargo:path",
2050
+ value: "../path-crate",
2051
+ },
2052
+ ],
2053
+ },
2054
+ ],
2055
+ [],
2056
+ [
2057
+ {
2058
+ type: "application",
2059
+ name: "setup-rust",
2060
+ version: "v1",
2061
+ purl: "pkg:github/moonrepo/setup-rust@v1",
2062
+ "bom-ref": "pkg:github/moonrepo/setup-rust@v1",
2063
+ properties: [
2064
+ {
2065
+ name: "cdx:github:action:uses",
2066
+ value: "moonrepo/setup-rust@v1",
2067
+ },
2068
+ { name: "cdx:github:action:disablesBuildCache", value: "true" },
2069
+ { name: "cdx:github:action:buildCacheEcosystem", value: "cargo" },
2070
+ ],
2071
+ },
2072
+ ],
2073
+ );
2074
+
2075
+ const findings = await evaluateRule(rule, bom);
2076
+ assert.strictEqual(findings.length, 0);
2077
+ });
2078
+
1437
2079
  it("should detect root authorized_keys without restrictions (OBOM-LNX-003)", async () => {
1438
2080
  const rules = await loadRules(RULES_DIR);
1439
2081
  const rule = rules.find((r) => r.id === "OBOM-LNX-003");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyclonedx/cdxgen",
3
- "version": "12.3.2",
3
+ "version": "12.3.3",
4
4
  "description": "Creates CycloneDX Software Bill of Materials (SBOM) from source or container image",
5
5
  "keywords": [
6
6
  "sbom",
@@ -98,6 +98,7 @@
98
98
  "files": [
99
99
  "*.js",
100
100
  "lib/**",
101
+ "!lib/**/*.poku.js",
101
102
  "bin/",
102
103
  "data/",
103
104
  "types/",