@cyclonedx/cdxgen 12.2.0 → 12.3.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 +242 -90
  2. package/bin/audit.js +191 -0
  3. package/bin/cdxgen.js +532 -168
  4. package/bin/convert.js +99 -0
  5. package/bin/evinse.js +23 -0
  6. package/bin/repl.js +339 -8
  7. package/bin/sign.js +8 -0
  8. package/bin/validate.js +8 -0
  9. package/bin/verify.js +8 -0
  10. package/data/container-knowledge-index.json +125 -0
  11. package/data/gtfobins-index.json +6296 -0
  12. package/data/lolbas-index.json +150 -0
  13. package/data/queries-darwin.json +63 -3
  14. package/data/queries-win.json +45 -3
  15. package/data/queries.json +74 -2
  16. package/data/rules/chrome-extensions.yaml +240 -0
  17. package/data/rules/ci-permissions.yaml +478 -18
  18. package/data/rules/container-risk.yaml +270 -0
  19. package/data/rules/obom-runtime.yaml +891 -0
  20. package/data/rules/package-integrity.yaml +49 -0
  21. package/data/spdx-export.schema.json +6794 -0
  22. package/data/spdx-model-v3.0.1.jsonld +15999 -0
  23. package/lib/audit/index.js +1924 -0
  24. package/lib/audit/index.poku.js +1488 -0
  25. package/lib/audit/progress.js +137 -0
  26. package/lib/audit/progress.poku.js +188 -0
  27. package/lib/audit/reporters.js +618 -0
  28. package/lib/audit/scoring.js +310 -0
  29. package/lib/audit/scoring.poku.js +341 -0
  30. package/lib/audit/targets.js +260 -0
  31. package/lib/audit/targets.poku.js +331 -0
  32. package/lib/cli/index.js +276 -68
  33. package/lib/cli/index.poku.js +368 -0
  34. package/lib/helpers/analyzer.js +1052 -5
  35. package/lib/helpers/analyzer.poku.js +301 -0
  36. package/lib/helpers/annotationFormatter.js +49 -0
  37. package/lib/helpers/annotationFormatter.poku.js +44 -0
  38. package/lib/helpers/bomUtils.js +36 -0
  39. package/lib/helpers/bomUtils.poku.js +51 -0
  40. package/lib/helpers/caxa.js +2 -2
  41. package/lib/helpers/chromextutils.js +1153 -0
  42. package/lib/helpers/chromextutils.poku.js +493 -0
  43. package/lib/helpers/ciParsers/githubActions.js +1632 -45
  44. package/lib/helpers/ciParsers/githubActions.poku.js +853 -1
  45. package/lib/helpers/containerRisk.js +186 -0
  46. package/lib/helpers/containerRisk.poku.js +52 -0
  47. package/lib/helpers/depsUtils.js +16 -0
  48. package/lib/helpers/depsUtils.poku.js +58 -1
  49. package/lib/helpers/display.js +245 -61
  50. package/lib/helpers/display.poku.js +162 -2
  51. package/lib/helpers/exportUtils.js +123 -0
  52. package/lib/helpers/exportUtils.poku.js +60 -0
  53. package/lib/helpers/formulationParsers.js +69 -0
  54. package/lib/helpers/formulationParsers.poku.js +44 -0
  55. package/lib/helpers/gtfobins.js +189 -0
  56. package/lib/helpers/gtfobins.poku.js +49 -0
  57. package/lib/helpers/lolbas.js +267 -0
  58. package/lib/helpers/lolbas.poku.js +39 -0
  59. package/lib/helpers/osqueryTransform.js +84 -0
  60. package/lib/helpers/osqueryTransform.poku.js +49 -0
  61. package/lib/helpers/provenanceUtils.js +193 -0
  62. package/lib/helpers/provenanceUtils.poku.js +145 -0
  63. package/lib/helpers/pylockutils.js +281 -0
  64. package/lib/helpers/pylockutils.poku.js +48 -0
  65. package/lib/helpers/registryProvenance.js +793 -0
  66. package/lib/helpers/registryProvenance.poku.js +452 -0
  67. package/lib/helpers/remote/dependency-track.js +84 -0
  68. package/lib/helpers/remote/dependency-track.poku.js +119 -0
  69. package/lib/helpers/source.js +1267 -0
  70. package/lib/helpers/source.poku.js +771 -0
  71. package/lib/helpers/spdxUtils.js +97 -0
  72. package/lib/helpers/spdxUtils.poku.js +70 -0
  73. package/lib/helpers/table.js +384 -0
  74. package/lib/helpers/table.poku.js +186 -0
  75. package/lib/helpers/unicodeScan.js +147 -0
  76. package/lib/helpers/unicodeScan.poku.js +45 -0
  77. package/lib/helpers/utils.js +882 -136
  78. package/lib/helpers/utils.poku.js +995 -91
  79. package/lib/managers/binary.js +29 -5
  80. package/lib/managers/docker.js +179 -52
  81. package/lib/managers/docker.poku.js +327 -28
  82. package/lib/managers/oci.js +107 -23
  83. package/lib/managers/oci.poku.js +132 -0
  84. package/lib/server/openapi.yaml +50 -0
  85. package/lib/server/server.js +228 -331
  86. package/lib/server/server.poku.js +220 -5
  87. package/lib/stages/postgen/annotator.js +7 -0
  88. package/lib/stages/postgen/annotator.poku.js +40 -0
  89. package/lib/stages/postgen/auditBom.js +20 -5
  90. package/lib/stages/postgen/auditBom.poku.js +1729 -67
  91. package/lib/stages/postgen/postgen.js +40 -0
  92. package/lib/stages/postgen/postgen.poku.js +47 -0
  93. package/lib/stages/postgen/ruleEngine.js +80 -2
  94. package/lib/stages/postgen/spdxConverter.js +796 -0
  95. package/lib/stages/postgen/spdxConverter.poku.js +341 -0
  96. package/lib/validator/bomValidator.js +232 -0
  97. package/lib/validator/bomValidator.poku.js +70 -0
  98. package/lib/validator/complianceRules.js +70 -7
  99. package/lib/validator/complianceRules.poku.js +30 -0
  100. package/lib/validator/reporters/annotations.js +2 -2
  101. package/lib/validator/reporters/console.js +13 -2
  102. package/lib/validator/reporters.poku.js +13 -0
  103. package/package.json +10 -8
  104. package/types/bin/audit.d.ts +3 -0
  105. package/types/bin/audit.d.ts.map +1 -0
  106. package/types/bin/convert.d.ts +3 -0
  107. package/types/bin/convert.d.ts.map +1 -0
  108. package/types/bin/repl.d.ts.map +1 -1
  109. package/types/lib/audit/index.d.ts +115 -0
  110. package/types/lib/audit/index.d.ts.map +1 -0
  111. package/types/lib/audit/progress.d.ts +27 -0
  112. package/types/lib/audit/progress.d.ts.map +1 -0
  113. package/types/lib/audit/reporters.d.ts +35 -0
  114. package/types/lib/audit/reporters.d.ts.map +1 -0
  115. package/types/lib/audit/scoring.d.ts +35 -0
  116. package/types/lib/audit/scoring.d.ts.map +1 -0
  117. package/types/lib/audit/targets.d.ts +63 -0
  118. package/types/lib/audit/targets.d.ts.map +1 -0
  119. package/types/lib/cli/index.d.ts +8 -0
  120. package/types/lib/cli/index.d.ts.map +1 -1
  121. package/types/lib/helpers/analyzer.d.ts +13 -0
  122. package/types/lib/helpers/analyzer.d.ts.map +1 -1
  123. package/types/lib/helpers/annotationFormatter.d.ts +23 -0
  124. package/types/lib/helpers/annotationFormatter.d.ts.map +1 -0
  125. package/types/lib/helpers/bomUtils.d.ts +5 -0
  126. package/types/lib/helpers/bomUtils.d.ts.map +1 -0
  127. package/types/lib/helpers/chromextutils.d.ts +97 -0
  128. package/types/lib/helpers/chromextutils.d.ts.map +1 -0
  129. package/types/lib/helpers/ciParsers/githubActions.d.ts +3 -8
  130. package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -1
  131. package/types/lib/helpers/containerRisk.d.ts +17 -0
  132. package/types/lib/helpers/containerRisk.d.ts.map +1 -0
  133. package/types/lib/helpers/depsUtils.d.ts.map +1 -1
  134. package/types/lib/helpers/display.d.ts +4 -1
  135. package/types/lib/helpers/display.d.ts.map +1 -1
  136. package/types/lib/helpers/exportUtils.d.ts +40 -0
  137. package/types/lib/helpers/exportUtils.d.ts.map +1 -0
  138. package/types/lib/helpers/formulationParsers.d.ts.map +1 -1
  139. package/types/lib/helpers/gtfobins.d.ts +17 -0
  140. package/types/lib/helpers/gtfobins.d.ts.map +1 -0
  141. package/types/lib/helpers/lolbas.d.ts +16 -0
  142. package/types/lib/helpers/lolbas.d.ts.map +1 -0
  143. package/types/lib/helpers/osqueryTransform.d.ts +7 -0
  144. package/types/lib/helpers/osqueryTransform.d.ts.map +1 -0
  145. package/types/lib/helpers/provenanceUtils.d.ts +90 -0
  146. package/types/lib/helpers/provenanceUtils.d.ts.map +1 -0
  147. package/types/lib/helpers/pylockutils.d.ts +51 -0
  148. package/types/lib/helpers/pylockutils.d.ts.map +1 -0
  149. package/types/lib/helpers/registryProvenance.d.ts +17 -0
  150. package/types/lib/helpers/registryProvenance.d.ts.map +1 -0
  151. package/types/lib/helpers/remote/dependency-track.d.ts +16 -0
  152. package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -0
  153. package/types/lib/helpers/source.d.ts +141 -0
  154. package/types/lib/helpers/source.d.ts.map +1 -0
  155. package/types/lib/helpers/spdxUtils.d.ts +2 -0
  156. package/types/lib/helpers/spdxUtils.d.ts.map +1 -0
  157. package/types/lib/helpers/table.d.ts +6 -0
  158. package/types/lib/helpers/table.d.ts.map +1 -0
  159. package/types/lib/helpers/unicodeScan.d.ts +46 -0
  160. package/types/lib/helpers/unicodeScan.d.ts.map +1 -0
  161. package/types/lib/helpers/utils.d.ts +30 -11
  162. package/types/lib/helpers/utils.d.ts.map +1 -1
  163. package/types/lib/managers/binary.d.ts.map +1 -1
  164. package/types/lib/managers/docker.d.ts.map +1 -1
  165. package/types/lib/managers/oci.d.ts.map +1 -1
  166. package/types/lib/server/server.d.ts +0 -35
  167. package/types/lib/server/server.d.ts.map +1 -1
  168. package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
  169. package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
  170. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  171. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  172. package/types/lib/stages/postgen/spdxConverter.d.ts +11 -0
  173. package/types/lib/stages/postgen/spdxConverter.d.ts.map +1 -0
  174. package/types/lib/validator/bomValidator.d.ts +1 -0
  175. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  176. package/types/lib/validator/complianceRules.d.ts.map +1 -1
  177. package/types/lib/validator/reporters/console.d.ts.map +1 -1
  178. package/types/bin/dependencies.d.ts +0 -3
  179. package/types/bin/dependencies.d.ts.map +0 -1
  180. package/types/bin/licenses.d.ts +0 -3
  181. package/types/bin/licenses.d.ts.map +0 -1
@@ -7,6 +7,7 @@ import { PackageURL } from "packageurl-js";
7
7
  import { mergeDependencies } from "../../helpers/depsUtils.js";
8
8
  import { addFormulationSection } from "../../helpers/formulationParsers.js";
9
9
  import { thoughtLog } from "../../helpers/logger.js";
10
+ import { buildReleaseNotesFromGit } from "../../helpers/source.js";
10
11
  import {
11
12
  DEBUG_MODE,
12
13
  dirNameStr,
@@ -107,6 +108,7 @@ export function postProcess(bomNSData, options, filePath) {
107
108
  filePath,
108
109
  bomNSData.formulationList,
109
110
  );
111
+ bomNSData.bomJson = applyReleaseNotes(bomNSData.bomJson, options, filePath);
110
112
  // Support for automatic annotations
111
113
  if (options.specVersion >= 1.6) {
112
114
  bomNSData.bomJson = annotate(bomNSData.bomJson, options);
@@ -116,6 +118,44 @@ export function postProcess(bomNSData, options, filePath) {
116
118
  return bomNSData;
117
119
  }
118
120
 
121
+ function applyReleaseNotes(bomJson, options, filePath) {
122
+ if (!options?.includeReleaseNotes) {
123
+ return bomJson;
124
+ }
125
+ const specVersion = Number(options.specVersion || 1.7);
126
+ if (specVersion < 1.6) {
127
+ const errorMessage =
128
+ "releaseNotes in metadata.tools.components requires CycloneDX spec version 1.6 or above.";
129
+ if (options.failOnError) {
130
+ throw new Error(errorMessage);
131
+ }
132
+ console.warn(errorMessage);
133
+ return bomJson;
134
+ }
135
+ const toolComponents = bomJson?.metadata?.tools?.components;
136
+ if (!Array.isArray(toolComponents) || !toolComponents.length) {
137
+ return bomJson;
138
+ }
139
+ const cdxgenToolComponent = toolComponents.find(
140
+ (comp) => comp?.group === "@cyclonedx" && comp?.name === "cdxgen",
141
+ );
142
+ if (!cdxgenToolComponent) {
143
+ return bomJson;
144
+ }
145
+ const releaseNotes = buildReleaseNotesFromGit(filePath, options);
146
+ if (!releaseNotes) {
147
+ const errorMessage =
148
+ "Unable to compute release notes. Provide --release-notes-current-tag and optionally --release-notes-previous-tag.";
149
+ if (options.failOnError) {
150
+ throw new Error(errorMessage);
151
+ }
152
+ console.warn(errorMessage);
153
+ return bomJson;
154
+ }
155
+ cdxgenToolComponent.releaseNotes = releaseNotes;
156
+ return bomJson;
157
+ }
158
+
119
159
  /**
120
160
  * Apply additional metadata based on components
121
161
  *
@@ -158,3 +158,50 @@ it("postProcess passes formulationList from bomNSData into the formulation secti
158
158
  "pixi-pkg from formulationList should appear in formulation components",
159
159
  );
160
160
  });
161
+
162
+ it("postProcess attaches releaseNotes to cdxgen metadata tool component", () => {
163
+ const bomNSData = {
164
+ bomJson: {
165
+ bomFormat: "CycloneDX",
166
+ specVersion: "1.7",
167
+ components: [],
168
+ dependencies: [],
169
+ metadata: {
170
+ tools: {
171
+ components: [
172
+ {
173
+ group: "@cyclonedx",
174
+ name: "cdxgen",
175
+ version: "12.3.0",
176
+ type: "application",
177
+ },
178
+ ],
179
+ },
180
+ properties: [],
181
+ },
182
+ },
183
+ };
184
+ const options = {
185
+ includeReleaseNotes: true,
186
+ releaseNotesCurrentTag: "v1.0.0",
187
+ releaseNotesPreviousTag: "v0.9.0",
188
+ specVersion: 1.7,
189
+ failOnError: true,
190
+ };
191
+ const result = postProcess(bomNSData, options);
192
+ const cdxTool = result.bomJson.metadata.tools.components[0];
193
+ assert.strictEqual(cdxTool.releaseNotes.title, "Release notes for v1.0.0");
194
+ assert.strictEqual(
195
+ cdxTool.releaseNotes.description,
196
+ "Changes between v0.9.0 and v1.0.0.",
197
+ );
198
+ assert.ok(cdxTool.releaseNotes.timestamp);
199
+ assert.deepStrictEqual(cdxTool.releaseNotes.tags, ["v1.0.0", "v0.9.0"]);
200
+ assert.ok(Array.isArray(cdxTool.releaseNotes.resolves));
201
+ for (const aresolve of cdxTool.releaseNotes.resolves) {
202
+ assert.ok(aresolve.type);
203
+ assert.ok(aresolve.id);
204
+ assert.ok(aresolve.name);
205
+ assert.ok(aresolve.description);
206
+ }
207
+ });
@@ -34,6 +34,66 @@ function extractProperty(obj, propName) {
34
34
  return prop?.value ?? null;
35
35
  }
36
36
 
37
+ function dedupeObjectsByIdentity(items) {
38
+ const seen = new Set();
39
+ const deduped = [];
40
+ (items || []).forEach((item) => {
41
+ if (!item) {
42
+ return;
43
+ }
44
+ const key =
45
+ item["bom-ref"] ||
46
+ item.purl ||
47
+ `${item.type || "unknown"}:${item.name || "unnamed"}:${item.version || ""}`;
48
+ if (seen.has(key)) {
49
+ return;
50
+ }
51
+ seen.add(key);
52
+ deduped.push(item);
53
+ });
54
+ return deduped;
55
+ }
56
+
57
+ function getFormulationEntries(bomJson) {
58
+ return Array.isArray(bomJson?.formulation) ? bomJson.formulation : [];
59
+ }
60
+
61
+ function getFormulationComponents(bomJson) {
62
+ return getFormulationEntries(bomJson).flatMap(
63
+ (entry) => entry?.components || [],
64
+ );
65
+ }
66
+
67
+ function getAuditComponents(bomJson) {
68
+ return dedupeObjectsByIdentity([
69
+ ...(Array.isArray(bomJson?.components) ? bomJson.components : []),
70
+ ...getFormulationComponents(bomJson),
71
+ ]);
72
+ }
73
+
74
+ function getAuditWorkflows(bomJson) {
75
+ return dedupeObjectsByIdentity(
76
+ getFormulationEntries(bomJson).flatMap((entry) => entry?.workflows || []),
77
+ );
78
+ }
79
+
80
+ function normalizeAttackMetadata(rule) {
81
+ const tactics = Array.isArray(rule?.attack?.tactics)
82
+ ? rule.attack.tactics
83
+ : [];
84
+ const techniques = Array.isArray(rule?.attack?.techniques)
85
+ ? rule.attack.techniques
86
+ : [];
87
+ return {
88
+ tactics: tactics
89
+ .filter((value) => typeof value === "string" && value.trim().length > 0)
90
+ .map((value) => value.trim()),
91
+ techniques: techniques
92
+ .filter((value) => typeof value === "string" && value.trim().length > 0)
93
+ .map((value) => value.trim()),
94
+ };
95
+ }
96
+
37
97
  /**
38
98
  * Helper: Check if property exists and equals expected value
39
99
  * Usage: $hasProp(component, 'cdx:foo', 'bar')
@@ -145,6 +205,15 @@ function registerCdxHelpers(expression) {
145
205
  expression.registerFunction("safeStr", (val) => {
146
206
  return val === null || val === undefined ? "" : String(val).trim();
147
207
  });
208
+ expression.registerFunction("auditComponents", (bomJson) =>
209
+ getAuditComponents(bomJson),
210
+ );
211
+ expression.registerFunction("auditWorkflows", (bomJson) =>
212
+ getAuditWorkflows(bomJson),
213
+ );
214
+ expression.registerFunction("formulationComponents", (bomJson) =>
215
+ getFormulationComponents(bomJson),
216
+ );
148
217
  return expression;
149
218
  }
150
219
 
@@ -217,6 +286,10 @@ export async function loadRules(rulesDir) {
217
286
  }
218
287
  rule.severity = rule.severity || "medium";
219
288
  rule.category = rule.category || "unknown";
289
+ const attack = normalizeAttackMetadata(rule);
290
+ if (attack.tactics.length || attack.techniques.length) {
291
+ rule.attack = attack;
292
+ }
220
293
  if (!["critical", "high", "medium", "low"].includes(rule.severity)) {
221
294
  console.warn(
222
295
  `Rule ${rule.id} has invalid severity '${rule.severity}'; defaulting to 'medium'`,
@@ -287,11 +360,13 @@ export async function evaluateRule(rule, bomJson) {
287
360
  return findings;
288
361
  }
289
362
  for (const item of matches) {
363
+ const attack = normalizeAttackMetadata(rule);
290
364
  const context = {
291
365
  ...item,
292
366
  bom: bomJson,
293
- components: bomJson.components || [],
294
- workflows: bomJson.formulation?.[0]?.workflows || [],
367
+ components: getAuditComponents(bomJson),
368
+ workflows: getAuditWorkflows(bomJson),
369
+ formulationComponents: getFormulationComponents(bomJson),
295
370
  services: bomJson.services || [],
296
371
  metadata: bomJson.metadata || {},
297
372
  };
@@ -327,6 +402,9 @@ export async function evaluateRule(rule, bomJson) {
327
402
  }
328
403
  }
329
404
  findings.push({
405
+ attack,
406
+ attackTactics: attack.tactics,
407
+ attackTechniques: attack.techniques,
330
408
  ruleId: rule.id,
331
409
  name: rule.name || rule.id,
332
410
  description: rule.description,