@cyclonedx/cdxgen 12.1.5 → 12.2.0

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 (181) hide show
  1. package/README.md +47 -39
  2. package/bin/cdxgen.js +175 -96
  3. package/bin/evinse.js +4 -4
  4. package/bin/repl.js +1 -1
  5. package/bin/sign.js +102 -0
  6. package/bin/validate.js +233 -0
  7. package/bin/verify.js +69 -28
  8. package/data/queries.json +1 -1
  9. package/data/rules/ci-permissions.yaml +186 -0
  10. package/data/rules/dependency-sources.yaml +123 -0
  11. package/data/rules/package-integrity.yaml +135 -0
  12. package/data/rules/vscode-extensions.yaml +228 -0
  13. package/lib/cli/index.js +327 -372
  14. package/lib/evinser/db.js +137 -0
  15. package/lib/{helpers → evinser}/db.poku.js +2 -6
  16. package/lib/evinser/evinser.js +2 -14
  17. package/lib/helpers/bomSigner.js +312 -0
  18. package/lib/helpers/bomSigner.poku.js +156 -0
  19. package/lib/helpers/ciParsers/azurePipelines.js +295 -0
  20. package/lib/helpers/ciParsers/azurePipelines.poku.js +253 -0
  21. package/lib/helpers/ciParsers/circleCi.js +286 -0
  22. package/lib/helpers/ciParsers/circleCi.poku.js +230 -0
  23. package/lib/helpers/ciParsers/common.js +24 -0
  24. package/lib/helpers/ciParsers/githubActions.js +636 -0
  25. package/lib/helpers/ciParsers/githubActions.poku.js +802 -0
  26. package/lib/helpers/ciParsers/gitlabCi.js +213 -0
  27. package/lib/helpers/ciParsers/gitlabCi.poku.js +247 -0
  28. package/lib/helpers/ciParsers/jenkins.js +181 -0
  29. package/lib/helpers/ciParsers/jenkins.poku.js +197 -0
  30. package/lib/helpers/depsUtils.js +203 -0
  31. package/lib/helpers/depsUtils.poku.js +150 -0
  32. package/lib/helpers/display.js +423 -4
  33. package/lib/helpers/envcontext.js +18 -3
  34. package/lib/helpers/formulationParsers.js +351 -0
  35. package/lib/helpers/logger.js +14 -0
  36. package/lib/helpers/protobom.js +9 -9
  37. package/lib/helpers/pythonutils.js +9 -0
  38. package/lib/helpers/utils.js +681 -406
  39. package/lib/helpers/utils.poku.js +55 -255
  40. package/lib/helpers/versutils.js +202 -0
  41. package/lib/helpers/versutils.poku.js +315 -0
  42. package/lib/helpers/vsixutils.js +1061 -0
  43. package/lib/helpers/vsixutils.poku.js +2247 -0
  44. package/lib/managers/binary.js +19 -19
  45. package/lib/managers/docker.js +108 -1
  46. package/lib/managers/oci.js +10 -0
  47. package/lib/managers/piptree.js +3 -9
  48. package/lib/parsers/npmrc.js +17 -13
  49. package/lib/parsers/npmrc.poku.js +41 -5
  50. package/lib/server/openapi.yaml +1 -1
  51. package/lib/server/server.js +40 -11
  52. package/lib/server/server.poku.js +123 -144
  53. package/lib/stages/postgen/annotator.js +1 -1
  54. package/lib/stages/postgen/auditBom.js +197 -0
  55. package/lib/stages/postgen/auditBom.poku.js +378 -0
  56. package/lib/stages/postgen/postgen.js +54 -1
  57. package/lib/stages/postgen/postgen.poku.js +90 -1
  58. package/lib/stages/postgen/ruleEngine.js +369 -0
  59. package/lib/stages/pregen/envAudit.js +299 -0
  60. package/lib/stages/pregen/envAudit.poku.js +572 -0
  61. package/lib/stages/pregen/pregen.js +12 -8
  62. package/lib/{helpers/validator.js → validator/bomValidator.js} +107 -47
  63. package/lib/validator/complianceEngine.js +241 -0
  64. package/lib/validator/complianceEngine.poku.js +168 -0
  65. package/lib/validator/complianceRules.js +1610 -0
  66. package/lib/validator/complianceRules.poku.js +328 -0
  67. package/lib/validator/index.js +222 -0
  68. package/lib/validator/index.poku.js +144 -0
  69. package/lib/validator/reporters/annotations.js +121 -0
  70. package/lib/validator/reporters/console.js +149 -0
  71. package/lib/validator/reporters/index.js +41 -0
  72. package/lib/validator/reporters/json.js +37 -0
  73. package/lib/validator/reporters/sarif.js +184 -0
  74. package/lib/validator/reporters.poku.js +150 -0
  75. package/package.json +8 -8
  76. package/types/bin/sign.d.ts +3 -0
  77. package/types/bin/sign.d.ts.map +1 -0
  78. package/types/bin/validate.d.ts +3 -0
  79. package/types/bin/validate.d.ts.map +1 -0
  80. package/types/helpers/utils.d.ts +0 -1
  81. package/types/lib/cli/index.d.ts +49 -52
  82. package/types/lib/cli/index.d.ts.map +1 -1
  83. package/types/lib/evinser/db.d.ts +34 -0
  84. package/types/lib/evinser/db.d.ts.map +1 -0
  85. package/types/lib/evinser/evinser.d.ts +63 -16
  86. package/types/lib/evinser/evinser.d.ts.map +1 -1
  87. package/types/lib/helpers/bomSigner.d.ts +27 -0
  88. package/types/lib/helpers/bomSigner.d.ts.map +1 -0
  89. package/types/lib/helpers/ciParsers/azurePipelines.d.ts +17 -0
  90. package/types/lib/helpers/ciParsers/azurePipelines.d.ts.map +1 -0
  91. package/types/lib/helpers/ciParsers/circleCi.d.ts +17 -0
  92. package/types/lib/helpers/ciParsers/circleCi.d.ts.map +1 -0
  93. package/types/lib/helpers/ciParsers/common.d.ts +11 -0
  94. package/types/lib/helpers/ciParsers/common.d.ts.map +1 -0
  95. package/types/lib/helpers/ciParsers/githubActions.d.ts +34 -0
  96. package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -0
  97. package/types/lib/helpers/ciParsers/gitlabCi.d.ts +17 -0
  98. package/types/lib/helpers/ciParsers/gitlabCi.d.ts.map +1 -0
  99. package/types/lib/helpers/ciParsers/jenkins.d.ts +17 -0
  100. package/types/lib/helpers/ciParsers/jenkins.d.ts.map +1 -0
  101. package/types/lib/helpers/depsUtils.d.ts +21 -0
  102. package/types/lib/helpers/depsUtils.d.ts.map +1 -0
  103. package/types/lib/helpers/display.d.ts +111 -11
  104. package/types/lib/helpers/display.d.ts.map +1 -1
  105. package/types/lib/helpers/envcontext.d.ts +19 -7
  106. package/types/lib/helpers/envcontext.d.ts.map +1 -1
  107. package/types/lib/helpers/formulationParsers.d.ts +50 -0
  108. package/types/lib/helpers/formulationParsers.d.ts.map +1 -0
  109. package/types/lib/helpers/logger.d.ts +15 -1
  110. package/types/lib/helpers/logger.d.ts.map +1 -1
  111. package/types/lib/helpers/protobom.d.ts +2 -2
  112. package/types/lib/helpers/pythonutils.d.ts +10 -1
  113. package/types/lib/helpers/pythonutils.d.ts.map +1 -1
  114. package/types/lib/helpers/utils.d.ts +532 -128
  115. package/types/lib/helpers/utils.d.ts.map +1 -1
  116. package/types/lib/helpers/versutils.d.ts +8 -0
  117. package/types/lib/helpers/versutils.d.ts.map +1 -0
  118. package/types/lib/helpers/vsixutils.d.ts +130 -0
  119. package/types/lib/helpers/vsixutils.d.ts.map +1 -0
  120. package/types/lib/managers/docker.d.ts +12 -31
  121. package/types/lib/managers/docker.d.ts.map +1 -1
  122. package/types/lib/managers/oci.d.ts +11 -1
  123. package/types/lib/managers/oci.d.ts.map +1 -1
  124. package/types/lib/managers/piptree.d.ts.map +1 -1
  125. package/types/lib/parsers/npmrc.d.ts +4 -1
  126. package/types/lib/parsers/npmrc.d.ts.map +1 -1
  127. package/types/lib/server/server.d.ts +21 -2
  128. package/types/lib/server/server.d.ts.map +1 -1
  129. package/types/lib/stages/postgen/auditBom.d.ts +20 -0
  130. package/types/lib/stages/postgen/auditBom.d.ts.map +1 -0
  131. package/types/lib/stages/postgen/postgen.d.ts +8 -1
  132. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  133. package/types/lib/stages/postgen/ruleEngine.d.ts +18 -0
  134. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -0
  135. package/types/lib/stages/pregen/envAudit.d.ts +8 -0
  136. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -0
  137. package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
  138. package/types/lib/{helpers/validator.d.ts → validator/bomValidator.d.ts} +1 -1
  139. package/types/lib/validator/bomValidator.d.ts.map +1 -0
  140. package/types/lib/validator/complianceEngine.d.ts +66 -0
  141. package/types/lib/validator/complianceEngine.d.ts.map +1 -0
  142. package/types/lib/validator/complianceRules.d.ts +70 -0
  143. package/types/lib/validator/complianceRules.d.ts.map +1 -0
  144. package/types/lib/validator/index.d.ts +70 -0
  145. package/types/lib/validator/index.d.ts.map +1 -0
  146. package/types/lib/validator/reporters/annotations.d.ts +31 -0
  147. package/types/lib/validator/reporters/annotations.d.ts.map +1 -0
  148. package/types/lib/validator/reporters/console.d.ts +30 -0
  149. package/types/lib/validator/reporters/console.d.ts.map +1 -0
  150. package/types/lib/validator/reporters/index.d.ts +21 -0
  151. package/types/lib/validator/reporters/index.d.ts.map +1 -0
  152. package/types/lib/validator/reporters/json.d.ts +11 -0
  153. package/types/lib/validator/reporters/json.d.ts.map +1 -0
  154. package/types/lib/validator/reporters/sarif.d.ts +16 -0
  155. package/types/lib/validator/reporters/sarif.d.ts.map +1 -0
  156. package/lib/helpers/db.js +0 -162
  157. package/lib/stages/pregen/env-audit.js +0 -34
  158. package/lib/stages/pregen/env-audit.poku.js +0 -290
  159. package/types/helpers/db.d.ts +0 -35
  160. package/types/helpers/db.d.ts.map +0 -1
  161. package/types/lib/helpers/db.d.ts +0 -35
  162. package/types/lib/helpers/db.d.ts.map +0 -1
  163. package/types/lib/helpers/validator.d.ts.map +0 -1
  164. package/types/lib/stages/pregen/env-audit.d.ts +0 -2
  165. package/types/lib/stages/pregen/env-audit.d.ts.map +0 -1
  166. package/types/managers/binary.d.ts +0 -37
  167. package/types/managers/binary.d.ts.map +0 -1
  168. package/types/managers/docker.d.ts +0 -56
  169. package/types/managers/docker.d.ts.map +0 -1
  170. package/types/managers/oci.d.ts +0 -2
  171. package/types/managers/oci.d.ts.map +0 -1
  172. package/types/managers/piptree.d.ts +0 -2
  173. package/types/managers/piptree.d.ts.map +0 -1
  174. package/types/server/server.d.ts +0 -34
  175. package/types/server/server.d.ts.map +0 -1
  176. package/types/stages/postgen/annotator.d.ts +0 -27
  177. package/types/stages/postgen/annotator.d.ts.map +0 -1
  178. package/types/stages/postgen/postgen.d.ts +0 -51
  179. package/types/stages/postgen/postgen.d.ts.map +0 -1
  180. package/types/stages/pregen/pregen.d.ts +0 -59
  181. package/types/stages/pregen/pregen.d.ts.map +0 -1
@@ -7,6 +7,7 @@ import { assert, describe, it, test } from "poku";
7
7
  import { parse } from "ssri";
8
8
  import { parse as loadYaml } from "yaml";
9
9
 
10
+ import { validateRefs } from "../validator/bomValidator.js";
10
11
  import {
11
12
  buildObjectForCocoaPod,
12
13
  buildObjectForGradleModule,
@@ -113,7 +114,6 @@ import {
113
114
  toGemModuleNames,
114
115
  yarnLockToIdentMap,
115
116
  } from "./utils.js";
116
- import { validateRefs } from "./validator.js";
117
117
 
118
118
  it("SSRI test", () => {
119
119
  // gopkg.lock hash
@@ -2596,12 +2596,15 @@ it("parse mix lock data", () => {
2596
2596
  it("parse github actions workflow data", () => {
2597
2597
  assert.deepStrictEqual(parseGitHubWorkflowData(null), []);
2598
2598
  let dep_list = parseGitHubWorkflowData("./.github/workflows/nodejs.yml");
2599
- assert.deepStrictEqual(dep_list.length, 8);
2599
+ assert.deepStrictEqual(dep_list.length, 13);
2600
2600
  assert.deepStrictEqual(dep_list[0], {
2601
+ "bom-ref":
2602
+ "pkg:github/actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd",
2603
+ type: "application",
2601
2604
  group: "actions",
2602
2605
  name: "checkout",
2603
- version: "6.0.2",
2604
- purl: "pkg:github/actions/checkout@6.0.2?commit=de0fac2e4500dabe0009e67214ff5f5447ce83dd",
2606
+ version: "de0fac2e4500dabe0009e67214ff5f5447ce83dd",
2607
+ purl: "pkg:github/actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd",
2605
2608
  properties: [
2606
2609
  {
2607
2610
  name: "SrcFile",
@@ -2611,6 +2614,10 @@ it("parse github actions workflow data", () => {
2611
2614
  name: "cdx:github:workflow:name",
2612
2615
  value: "Node CI",
2613
2616
  },
2617
+ {
2618
+ name: "cdx:github:workflow:file",
2619
+ value: "./.github/workflows/nodejs.yml",
2620
+ },
2614
2621
  {
2615
2622
  name: "cdx:github:job:name",
2616
2623
  value: "read-node-versions",
@@ -2631,277 +2638,40 @@ it("parse github actions workflow data", () => {
2631
2638
  name: "cdx:github:action:isShaPinned",
2632
2639
  value: "true",
2633
2640
  },
2634
- {
2635
- name: "cdx:github:workflow:concurrencyGroup",
2636
- value:
2637
- "${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}",
2638
- },
2639
2641
  {
2640
2642
  name: "cdx:actions:isOfficial",
2641
2643
  value: "true",
2642
2644
  },
2645
+ {
2646
+ name: "cdx:github:checkout:persistCredentials",
2647
+ value: "false",
2648
+ },
2643
2649
  {
2644
2650
  name: "cdx:github:workflow:triggers",
2645
2651
  value: "pull_request,push,workflow_dispatch",
2646
2652
  },
2647
2653
  ],
2654
+ scope: "required",
2648
2655
  evidence: {
2649
- identity: {
2650
- field: "purl",
2651
- confidence: 0.7,
2652
- methods: [
2653
- {
2654
- technique: "source-code-analysis",
2655
- confidence: 0.7,
2656
- value: "./.github/workflows/nodejs.yml",
2657
- },
2658
- ],
2659
- },
2660
- },
2661
- });
2662
- dep_list = parseGitHubWorkflowData("./test/data/github-actions-tj.yaml");
2663
- assert.deepStrictEqual(dep_list.length, 4);
2664
- assert.deepStrictEqual(dep_list, [
2665
- {
2666
- group: "pixel",
2667
- name: "steamcmd",
2668
- version: "1.2.7",
2669
- purl: "pkg:github/pixel/steamcmd@1.2.7?commit=foo",
2670
- properties: [
2656
+ identity: [
2671
2657
  {
2672
- name: "SrcFile",
2673
- value: "./test/data/github-actions-tj.yaml",
2674
- },
2675
- {
2676
- name: "cdx:github:workflow:name",
2677
- value: "Testing",
2678
- },
2679
- {
2680
- name: "cdx:github:job:name",
2681
- value: "vulnerable-actions",
2682
- },
2683
- {
2684
- name: "cdx:github:job:runner",
2685
- value: "ubuntu-latest",
2686
- },
2687
- {
2688
- name: "cdx:github:action:uses",
2689
- value: "pixel/steamcmd@foo",
2690
- },
2691
- {
2692
- name: "cdx:github:action:versionPinningType",
2693
- value: "tag",
2694
- },
2695
- {
2696
- name: "cdx:github:action:isShaPinned",
2697
- value: "false",
2698
- },
2699
- {
2700
- name: "cdx:github:step:name",
2701
- value: "Test action 1",
2702
- },
2703
- {
2704
- name: "cdx:github:workflow:triggers",
2705
- value: "push,pull_request_target",
2706
- },
2707
- ],
2708
- evidence: {
2709
- identity: {
2710
- field: "purl",
2711
- confidence: 0.7,
2712
- methods: [
2713
- {
2714
- technique: "source-code-analysis",
2715
- confidence: 0.7,
2716
- value: "./test/data/github-actions-tj.yaml",
2717
- },
2718
- ],
2719
- },
2720
- },
2721
- },
2722
- {
2723
- group: "tj",
2724
- name: "branch",
2725
- version: "8.2.0",
2726
- purl: "pkg:github/tj/branch@8.2.0?commit=47dd",
2727
- properties: [
2728
- {
2729
- name: "SrcFile",
2730
- value: "./test/data/github-actions-tj.yaml",
2731
- },
2732
- {
2733
- name: "cdx:github:workflow:name",
2734
- value: "Testing",
2735
- },
2736
- {
2737
- name: "cdx:github:job:name",
2738
- value: "vulnerable-actions",
2739
- },
2740
- {
2741
- name: "cdx:github:job:runner",
2742
- value: "ubuntu-latest",
2743
- },
2744
- {
2745
- name: "cdx:github:action:uses",
2746
- value: "tj/branch@47dd",
2747
- },
2748
- {
2749
- name: "cdx:github:action:versionPinningType",
2750
- value: "tag",
2751
- },
2752
- {
2753
- name: "cdx:github:action:isShaPinned",
2754
- value: "false",
2755
- },
2756
- {
2757
- name: "cdx:github:step:name",
2758
- value: "Test action 2",
2759
- },
2760
- {
2761
- name: "cdx:github:workflow:triggers",
2762
- value: "push,pull_request_target",
2763
- },
2764
- ],
2765
- evidence: {
2766
- identity: {
2767
2658
  field: "purl",
2768
- confidence: 0.7,
2769
- methods: [
2770
- {
2771
- technique: "source-code-analysis",
2772
- confidence: 0.7,
2773
- value: "./test/data/github-actions-tj.yaml",
2774
- },
2775
- ],
2776
- },
2777
- },
2778
- },
2779
- {
2780
- group: "tj",
2781
- name: "branch2",
2782
- version: "08",
2783
- purl: "pkg:github/tj/branch2@08?tag=v0.0.18",
2784
- properties: [
2785
- {
2786
- name: "SrcFile",
2787
- value: "./test/data/github-actions-tj.yaml",
2788
- },
2789
- {
2790
- name: "cdx:github:workflow:name",
2791
- value: "Testing",
2792
- },
2793
- {
2794
- name: "cdx:github:job:name",
2795
- value: "vulnerable-actions",
2796
- },
2797
- {
2798
- name: "cdx:github:job:runner",
2799
- value: "ubuntu-latest",
2800
- },
2801
- {
2802
- name: "cdx:github:action:uses",
2803
- value: "tj/branch2@v0.0.18",
2804
- },
2805
- {
2806
- name: "cdx:github:action:versionPinningType",
2807
- value: "tag",
2808
- },
2809
- {
2810
- name: "cdx:github:action:isShaPinned",
2811
- value: "false",
2812
- },
2813
- {
2814
- name: "cdx:github:step:name",
2815
- value: "Test action 3",
2816
- },
2817
- {
2818
- name: "cdx:github:workflow:triggers",
2819
- value: "push,pull_request_target",
2820
- },
2821
- ],
2822
- evidence: {
2823
- identity: {
2824
- field: "purl",
2825
- confidence: 0.7,
2659
+ confidence: 0.5,
2826
2660
  methods: [
2827
2661
  {
2828
2662
  technique: "source-code-analysis",
2829
- confidence: 0.7,
2830
- value: "./test/data/github-actions-tj.yaml",
2663
+ confidence: 0.5,
2664
+ value: "./.github/workflows/nodejs.yml",
2831
2665
  },
2832
2666
  ],
2833
2667
  },
2834
- },
2835
- },
2836
- {
2837
- group: "github/codeql-action",
2838
- name: "upload-sarif",
2839
- version: "3.30.3",
2840
- purl: "pkg:github/github/codeql-action/upload-sarif@3.30.3?commit=192325c86100d080feab897ff886c34abd4c83a3",
2841
- properties: [
2842
- {
2843
- name: "SrcFile",
2844
- value: "./test/data/github-actions-tj.yaml",
2845
- },
2846
- {
2847
- name: "cdx:github:workflow:name",
2848
- value: "Testing",
2849
- },
2850
- {
2851
- name: "cdx:github:job:name",
2852
- value: "vulnerable-actions",
2853
- },
2854
- {
2855
- name: "cdx:github:job:runner",
2856
- value: "ubuntu-latest",
2857
- },
2858
- {
2859
- name: "cdx:github:action:uses",
2860
- value:
2861
- "github/codeql-action/upload-sarif@192325c86100d080feab897ff886c34abd4c83a3",
2862
- },
2863
- {
2864
- name: "cdx:github:action:versionPinningType",
2865
- value: "sha",
2866
- },
2867
- {
2868
- name: "cdx:github:action:isShaPinned",
2869
- value: "true",
2870
- },
2871
- {
2872
- name: "cdx:github:step:name",
2873
- value: "Upload to code-scanning",
2874
- },
2875
- {
2876
- name: "cdx:actions:isOfficial",
2877
- value: "true",
2878
- },
2879
- {
2880
- name: "cdx:actions:isVerified",
2881
- value: "true",
2882
- },
2883
- {
2884
- name: "cdx:github:workflow:triggers",
2885
- value: "push,pull_request_target",
2886
- },
2887
2668
  ],
2888
- evidence: {
2889
- identity: {
2890
- field: "purl",
2891
- confidence: 0.7,
2892
- methods: [
2893
- {
2894
- technique: "source-code-analysis",
2895
- confidence: 0.7,
2896
- value: "./test/data/github-actions-tj.yaml",
2897
- },
2898
- ],
2899
- },
2900
- },
2901
2669
  },
2902
- ]);
2670
+ });
2671
+ dep_list = parseGitHubWorkflowData("./test/data/github-actions-tj.yaml");
2672
+ assert.deepStrictEqual(dep_list.length, 4);
2903
2673
  dep_list = parseGitHubWorkflowData("./.github/workflows/repotests.yml");
2904
- assert.deepStrictEqual(dep_list.length, 17);
2674
+ assert.deepStrictEqual(dep_list.length, 90);
2905
2675
  });
2906
2676
  // biome-ignore-end lint/suspicious/noTemplateCurlyInString: fp
2907
2677
 
@@ -4472,7 +4242,10 @@ it("pnpmMetadata with scoped packages", async () => {
4472
4242
  it("pnpmMetadata integration with parsePnpmLock", async () => {
4473
4243
  // Test that the integration works by parsing a real pnpm lock file
4474
4244
  const parsedList = await parsePnpmLock("./pnpm-lock.yaml");
4475
-
4245
+ const externalRefDistPackages = parsedList.pkgList.filter((pkg) =>
4246
+ pkg.externalReferences?.some((p) => p.type === "distribution"),
4247
+ );
4248
+ assert.ok(externalRefDistPackages.length > 0);
4476
4249
  // Check that some packages have been enhanced with LocalNodeModulesPath
4477
4250
  const enhancedPackages = parsedList.pkgList.filter((pkg) =>
4478
4251
  pkg.properties?.some((p) => p.name === "LocalNodeModulesPath"),
@@ -5694,6 +5467,33 @@ it("parseComposerLock", () => {
5694
5467
  ref: "pkg:composer/doctrine/annotations@v1.2.1",
5695
5468
  dependsOn: ["pkg:composer/doctrine/lexer@v1.0"],
5696
5469
  });
5470
+
5471
+ // Platform requirements (php, ext-*) must not appear in rootList
5472
+ const platformRootRequires = {
5473
+ php: "^7.1.3|^8",
5474
+ "ext-SimpleXML": "*",
5475
+ "ext-dom": "*",
5476
+ "amphp/amp": "^2.1",
5477
+ "amphp/byte-stream": "^1.5",
5478
+ };
5479
+ retMap = parseComposerLock(
5480
+ "./test/data/composer-2.lock",
5481
+ platformRootRequires,
5482
+ );
5483
+ assert.ok(
5484
+ !retMap.rootList.some((p) => p.name === "php"),
5485
+ "php must not be in rootList",
5486
+ );
5487
+ assert.ok(
5488
+ !retMap.rootList.some((p) => p.name?.startsWith("ext-")),
5489
+ "ext-* must not be in rootList",
5490
+ );
5491
+ // Regular packages that are in rootRequires should still be in rootList
5492
+ // Note: apkg.name is basename(pkg.name), so "amphp/amp" → name "amp"
5493
+ assert.ok(
5494
+ retMap.rootList.some((p) => p.name === "amp"),
5495
+ "amphp/amp should be in rootList",
5496
+ );
5697
5497
  });
5698
5498
 
5699
5499
  it("parseComposerJson", () => {
@@ -0,0 +1,202 @@
1
+ function parseVersion(v) {
2
+ const m = v.match(/^([><=^~]+)?(.*)$/);
3
+ const ver = m ? m[2] : v;
4
+ if (ver === "*")
5
+ return { major: 0, minor: 0, patch: 0, pre: "", op: "", isStar: true };
6
+ const parts = ver.split("-");
7
+ const main = parts[0].split(".");
8
+ return {
9
+ op: m ? m[1] || "" : "",
10
+ major: Number.parseInt(main[0] || "0", 10),
11
+ minor: Number.parseInt(main[1] || "0", 10),
12
+ patch: Number.parseInt(main[2] || "0", 10),
13
+ pre: parts.slice(1).join("-"),
14
+ };
15
+ }
16
+
17
+ /**
18
+ * Converts a package.json npm version specifier to a VERS format range.
19
+ *
20
+ * @param {string} versionString - The native npm semver string.
21
+ * @returns {string} The formatted vers:npm range string.
22
+ */
23
+ export function toVersRange(versionString) {
24
+ if (!versionString || typeof versionString !== "string") {
25
+ return "";
26
+ }
27
+ let str = versionString.trim();
28
+ if (!str) {
29
+ return "";
30
+ }
31
+ if (str === "latest" || str.startsWith("workspace:")) {
32
+ return "";
33
+ }
34
+ if (str === "*") {
35
+ return "vers:npm/*";
36
+ }
37
+ // Replace hyphen ranges: A - B -> >=A <=B
38
+ str = str.replace(/([\w.-]+)\s+-\s+([\w.-]+)/g, ">= $1 <= $2");
39
+
40
+ // Split logical ORs
41
+ const ors = str.split("||").map((s) => s.trim());
42
+ const allBounds = [];
43
+
44
+ for (let part of ors) {
45
+ // Normalize spaces after operators to attach them to the version
46
+ part = part.replace(/([><=^~]+)\s+/g, "$1");
47
+ part = part.replace(/\s+/g, " ");
48
+
49
+ const tokens = part.split(" ").filter(Boolean);
50
+
51
+ for (let token of tokens) {
52
+ // Strip the 'v' prefix if present (e.g. >=v1.2.3 -> >=1.2.3)
53
+ token = token.replace(/^([><=^~]+)?v/i, (_match, op) => op || "");
54
+
55
+ if (token === "*") {
56
+ allBounds.push("*");
57
+ continue;
58
+ }
59
+
60
+ const match = token.match(/^([><=^~]+)?(.*)$/);
61
+ const op = match[1] || "";
62
+ let ver = match[2];
63
+
64
+ if (ver === "*") {
65
+ allBounds.push("*");
66
+ continue;
67
+ }
68
+
69
+ // Pad versions (e.g., '1' -> '1.0.0', '1.1' -> '1.1.0')
70
+ if (/^\d+$/.test(ver)) {
71
+ ver += ".0.0";
72
+ } else if (/^\d+\.\d+$/.test(ver)) {
73
+ ver += ".0";
74
+ }
75
+
76
+ // Handle .x or .* ranges
77
+ if (ver.endsWith(".x") || ver.endsWith(".*")) {
78
+ const parts = ver.split(".");
79
+ if (parts[1] === "x" || parts[1] === "*") {
80
+ const M = Number.parseInt(parts[0], 10);
81
+ allBounds.push(`>=${M}.0.0`, `<${M + 1}.0.0`);
82
+ } else if (parts[2] === "x" || parts[2] === "*") {
83
+ const M = parts[0];
84
+ const m_minor = Number.parseInt(parts[1], 10);
85
+ allBounds.push(`>=${M}.${m_minor}.0`, `<${M}.${m_minor + 1}.0`);
86
+ }
87
+ continue;
88
+ }
89
+
90
+ // Caret (^) expansion
91
+ if (op === "^") {
92
+ const m = ver.match(/^(\d+)\.(\d+)\.(\d+)(.*)$/);
93
+ if (!m) {
94
+ allBounds.push(`${op}${ver}`);
95
+ continue;
96
+ }
97
+ const M = Number.parseInt(m[1], 10);
98
+ const m_minor = Number.parseInt(m[2], 10);
99
+ const p = Number.parseInt(m[3], 10);
100
+ let upper;
101
+ if (M > 0) {
102
+ upper = `${M + 1}.0.0`;
103
+ } else if (m_minor > 0) {
104
+ upper = `0.${m_minor + 1}.0`;
105
+ } else {
106
+ upper = `0.0.${p + 1}`;
107
+ }
108
+ allBounds.push(`>=${ver}`, `<${upper}`);
109
+ continue;
110
+ }
111
+
112
+ // Tilde (~) expansion
113
+ if (op === "~") {
114
+ const m = ver.match(/^(\d+)\.(\d+)\.(\d+)(.*)$/);
115
+ if (!m) {
116
+ allBounds.push(`${op}${ver}`);
117
+ continue;
118
+ }
119
+ if (ver.includes("-pre")) {
120
+ const sv = parseVersion(ver);
121
+ const upper = `${sv.major}.${sv.minor}.0`;
122
+ const upper_1 = `${sv.major}.${sv.minor}.1`;
123
+ allBounds.push(`>=${ver}`, `<${upper}`, `>=${upper}`, `<${upper_1}`);
124
+ continue;
125
+ }
126
+ const M = Number.parseInt(m[1], 10);
127
+ const m_minor = Number.parseInt(m[2], 10);
128
+ const upper = `${M}.${m_minor + 1}.0`;
129
+ allBounds.push(`>=${ver}`, `<${upper}`);
130
+ continue;
131
+ }
132
+
133
+ if (op === "=") {
134
+ allBounds.push(ver);
135
+ continue;
136
+ }
137
+
138
+ // Exact fallback matches
139
+ if (op === "") {
140
+ allBounds.push(ver);
141
+ continue;
142
+ }
143
+
144
+ allBounds.push(op + ver);
145
+ }
146
+ }
147
+
148
+ // Sort all bounded intervals linearly mapped by semver precedence
149
+ allBounds.sort((aStr, bStr) => {
150
+ if (aStr === "*" && bStr === "*") return 0;
151
+ if (aStr === "*") return -1;
152
+ if (bStr === "*") return 1;
153
+
154
+ const a = parseVersion(aStr);
155
+ const b = parseVersion(bStr);
156
+
157
+ if (a.major !== b.major) return a.major - b.major;
158
+ if (a.minor !== b.minor) return a.minor - b.minor;
159
+ if (a.patch !== b.patch) return a.patch - b.patch;
160
+
161
+ if (a.pre && !b.pre) return -1;
162
+ if (!a.pre && b.pre) return 1;
163
+
164
+ if (a.pre && b.pre) {
165
+ if (a.pre !== b.pre) {
166
+ const aPre = a.pre.split(".");
167
+ const bPre = b.pre.split(".");
168
+ for (let i = 0; i < Math.max(aPre.length, bPre.length); i++) {
169
+ const ap = aPre[i];
170
+ const bp = bPre[i];
171
+
172
+ if (ap === undefined) return -1;
173
+ if (bp === undefined) return 1;
174
+
175
+ const apNum = /^\d+$/.test(ap);
176
+ const bpNum = /^\d+$/.test(bp);
177
+
178
+ if (apNum && bpNum) {
179
+ const diff = Number.parseInt(ap, 10) - Number.parseInt(bp, 10);
180
+ if (diff !== 0) return diff;
181
+ } else if (apNum && !bpNum) {
182
+ return -1;
183
+ } else if (!apNum && bpNum) {
184
+ return 1;
185
+ } else {
186
+ if (ap < bp) return -1;
187
+ if (ap > bp) return 1;
188
+ }
189
+ }
190
+ }
191
+ }
192
+
193
+ const opOrder = { "<": 1, "<=": 2, "": 3, ">=": 4, ">": 5 };
194
+ const aOp = opOrder[a.op] || 3;
195
+ const bOp = opOrder[b.op] || 3;
196
+ if (aOp !== bOp) return aOp - bOp;
197
+
198
+ return 0;
199
+ });
200
+
201
+ return `vers:npm/${allBounds.join("|")}`;
202
+ }