@cyclonedx/cdxgen 8.0.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.
package/binary.js ADDED
@@ -0,0 +1,507 @@
1
+ const os = require("os");
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+ const { spawnSync } = require("child_process");
5
+ const { PackageURL } = require("packageurl-js");
6
+ const isWin = require("os").platform() === "win32";
7
+
8
+ // Debug mode flag
9
+ const DEBUG_MODE =
10
+ process.env.SCAN_DEBUG_MODE === "debug" ||
11
+ process.env.SHIFTLEFT_LOGGING_LEVEL === "debug" ||
12
+ process.env.NODE_ENV === "development";
13
+
14
+ let platform = os.platform();
15
+ let extn = "";
16
+ if (platform == "win32") {
17
+ platform = "windows";
18
+ extn = ".exe";
19
+ }
20
+
21
+ let arch = os.arch();
22
+ switch (arch) {
23
+ case "x32":
24
+ arch = "386";
25
+ break;
26
+ case "x64":
27
+ arch = "amd64";
28
+ break;
29
+ }
30
+
31
+ // Retrieve the cdxgen plugins directory
32
+ let CDXGEN_PLUGINS_DIR = process.env.CDXGEN_PLUGINS_DIR;
33
+ // Is there a non-empty local plugins directory
34
+ if (
35
+ !CDXGEN_PLUGINS_DIR &&
36
+ fs.existsSync(path.join(__dirname, "plugins")) &&
37
+ fs.existsSync(path.join(__dirname, "plugins", "goversion"))
38
+ ) {
39
+ CDXGEN_PLUGINS_DIR = path.join(__dirname, "plugins");
40
+ }
41
+ // Is there a non-empty local node_modules directory
42
+ if (
43
+ !CDXGEN_PLUGINS_DIR &&
44
+ fs.existsSync(
45
+ path.join(
46
+ __dirname,
47
+ "node_modules",
48
+ "@cyclonedx",
49
+ "cdxgen-plugins-bin",
50
+ "plugins"
51
+ )
52
+ ) &&
53
+ fs.existsSync(
54
+ path.join(
55
+ __dirname,
56
+ "node_modules",
57
+ "@cyclonedx",
58
+ "cdxgen-plugins-bin",
59
+ "plugins",
60
+ "goversion"
61
+ )
62
+ )
63
+ ) {
64
+ CDXGEN_PLUGINS_DIR = path.join(
65
+ __dirname,
66
+ "node_modules",
67
+ "@cyclonedx",
68
+ "cdxgen-plugins-bin",
69
+ "plugins"
70
+ );
71
+ }
72
+
73
+ if (!CDXGEN_PLUGINS_DIR) {
74
+ let globalNodePath = process.env.GLOBAL_NODE_MODULES_PATH || undefined;
75
+ if (!globalNodePath) {
76
+ let result = spawnSync(
77
+ isWin ? "npm.cmd" : "npm",
78
+ ["root", "--quiet", "-g"],
79
+ {
80
+ encoding: "utf-8"
81
+ }
82
+ );
83
+ if (result) {
84
+ const stdout = result.stdout;
85
+ if (stdout) {
86
+ globalNodePath = Buffer.from(stdout).toString().trim() + "/";
87
+ }
88
+ }
89
+ }
90
+ const globalPlugins = path.join(
91
+ globalNodePath,
92
+ "@cyclonedx",
93
+ "cdxgen-plugins-bin",
94
+ "plugins"
95
+ );
96
+ if (fs.existsSync(globalPlugins)) {
97
+ CDXGEN_PLUGINS_DIR = globalPlugins;
98
+ if (DEBUG_MODE) {
99
+ console.log("Found global plugins", CDXGEN_PLUGINS_DIR);
100
+ }
101
+ }
102
+ }
103
+
104
+ if (!CDXGEN_PLUGINS_DIR) {
105
+ if (DEBUG_MODE) {
106
+ console.warn(
107
+ "cdxgen plugins was not found. Please install with npm install -g @cyclonedx/cdxgen-plugins-bin"
108
+ );
109
+ }
110
+ CDXGEN_PLUGINS_DIR = "";
111
+ }
112
+ let GOVERSION_BIN = null;
113
+ if (fs.existsSync(path.join(CDXGEN_PLUGINS_DIR, "goversion"))) {
114
+ GOVERSION_BIN = path.join(
115
+ CDXGEN_PLUGINS_DIR,
116
+ "goversion",
117
+ "goversion-" + platform + "-" + arch + extn
118
+ );
119
+ }
120
+ let TRIVY_BIN = null;
121
+ if (fs.existsSync(path.join(CDXGEN_PLUGINS_DIR, "trivy"))) {
122
+ TRIVY_BIN = path.join(
123
+ CDXGEN_PLUGINS_DIR,
124
+ "trivy",
125
+ "trivy-cdxgen-" + platform + "-" + arch + extn
126
+ );
127
+ } else if (process.env.TRIVY_CMD) {
128
+ TRIVY_BIN = process.env.TRIVY_CMD;
129
+ }
130
+ let CARGO_AUDITABLE_BIN = null;
131
+ if (fs.existsSync(path.join(CDXGEN_PLUGINS_DIR, "cargo-auditable"))) {
132
+ CARGO_AUDITABLE_BIN = path.join(
133
+ CDXGEN_PLUGINS_DIR,
134
+ "cargo-auditable",
135
+ "cargo-auditable-cdxgen-" + platform + "-" + arch + extn
136
+ );
137
+ } else if (process.env.CARGO_AUDITABLE_CMD) {
138
+ CARGO_AUDITABLE_BIN = process.env.CARGO_AUDITABLE_CMD;
139
+ }
140
+ let OSQUERY_BIN = null;
141
+ if (fs.existsSync(path.join(CDXGEN_PLUGINS_DIR, "osquery"))) {
142
+ OSQUERY_BIN = path.join(
143
+ CDXGEN_PLUGINS_DIR,
144
+ "osquery",
145
+ "osqueryi-" + platform + "-" + arch + extn
146
+ );
147
+ } else if (process.env.OSQUERY_CMD) {
148
+ OSQUERY_BIN = process.env.OSQUERY_CMD;
149
+ }
150
+
151
+ const OS_DISTRO_ALIAS = {
152
+ "ubuntu-4.10": "warty",
153
+ "ubuntu-5.04": "hoary",
154
+ "ubuntu-5.10": "breezy",
155
+ "ubuntu-6.06": "dapper",
156
+ "ubuntu-6.10": "edgy",
157
+ "ubuntu-7.04": "feisty",
158
+ "ubuntu-7.10": "gutsy",
159
+ "ubuntu-8.04": "hardy",
160
+ "ubuntu-8.10": "intrepid",
161
+ "ubuntu-9.04": "jaunty",
162
+ "ubuntu-9.10": "karmic",
163
+ "ubuntu-10.04": "lucid",
164
+ "ubuntu-10.10": "maverick",
165
+ "ubuntu-11.04": "natty",
166
+ "ubuntu-11.10": "oneiric",
167
+ "ubuntu-12.04": "precise",
168
+ "ubuntu-12.10": "quantal",
169
+ "ubuntu-13.04": "raring",
170
+ "ubuntu-13.10": "saucy",
171
+ "ubuntu-14.04": "trusty",
172
+ "ubuntu-14.10": "utopic",
173
+ "ubuntu-15.04": "vivid",
174
+ "ubuntu-15.10": "wily",
175
+ "ubuntu-16.04": "xenial",
176
+ "ubuntu-16.10": "yakkety",
177
+ "ubuntu-17.04": "zesty",
178
+ "ubuntu-17.10": "artful",
179
+ "ubuntu-18.04": "bionic",
180
+ "ubuntu-18.10": "cosmic",
181
+ "ubuntu-19.04": "disco",
182
+ "ubuntu-19.10": "eoan",
183
+ "ubuntu-20.04": "focal",
184
+ "ubuntu-20.10": "groovy",
185
+ "ubuntu-23.04": "lunar",
186
+ "debian-14": "forky",
187
+ "debian-14.5": "forky",
188
+ "debian-13": "trixie",
189
+ "debian-13.5": "trixie",
190
+ "debian-12": "bookworm",
191
+ "debian-12.5": "bookworm",
192
+ "debian-11": "bullseye",
193
+ "debian-11.5": "bullseye",
194
+ "debian-10": "buster",
195
+ "debian-10.5": "buster",
196
+ "debian-9": "stretch",
197
+ "debian-9.5": "stretch",
198
+ "debian-8": "jessie",
199
+ "debian-8.5": "jessie",
200
+ "debian-7": "wheezy",
201
+ "debian-7.5": "wheezy",
202
+ "debian-6": "squeeze",
203
+ "debian-5": "lenny",
204
+ "debian-4": "etch",
205
+ "debian-3.1": "sarge",
206
+ "debian-3": "woody",
207
+ "debian-2.2": "potato",
208
+ "debian-2.1": "slink",
209
+ "debian-2": "hamm",
210
+ "debian-1.3": "bo",
211
+ "debian-1.2": "rex",
212
+ "debian-1.1": "buzz"
213
+ };
214
+
215
+ const getGoBuildInfo = (src) => {
216
+ if (GOVERSION_BIN) {
217
+ let result = spawnSync(GOVERSION_BIN, [src], {
218
+ encoding: "utf-8"
219
+ });
220
+ if (result.status !== 0 || result.error) {
221
+ if (result.stdout || result.stderr) {
222
+ console.error(result.stdout, result.stderr);
223
+ }
224
+ if (DEBUG_MODE) {
225
+ console.log("Falling back to go version command");
226
+ }
227
+ result = spawnSync("go", ["version", "-v", "-m", src], {
228
+ encoding: "utf-8"
229
+ });
230
+ if (result.status !== 0 || result.error) {
231
+ if (result.stdout || result.stderr) {
232
+ console.error(result.stdout, result.stderr);
233
+ }
234
+ }
235
+ }
236
+ if (result) {
237
+ const stdout = result.stdout;
238
+ if (stdout) {
239
+ const cmdOutput = Buffer.from(stdout).toString();
240
+ return cmdOutput;
241
+ }
242
+ }
243
+ }
244
+ return undefined;
245
+ };
246
+ exports.getGoBuildInfo = getGoBuildInfo;
247
+
248
+ const getCargoAuditableInfo = (src) => {
249
+ if (CARGO_AUDITABLE_BIN) {
250
+ let result = spawnSync(CARGO_AUDITABLE_BIN, [src], {
251
+ encoding: "utf-8"
252
+ });
253
+ if (result.status !== 0 || result.error) {
254
+ if (result.stdout || result.stderr) {
255
+ console.error(result.stdout, result.stderr);
256
+ }
257
+ }
258
+ if (result) {
259
+ const stdout = result.stdout;
260
+ if (stdout) {
261
+ const cmdOutput = Buffer.from(stdout).toString();
262
+ return cmdOutput;
263
+ }
264
+ }
265
+ }
266
+ return undefined;
267
+ };
268
+ exports.getCargoAuditableInfo = getCargoAuditableInfo;
269
+
270
+ const getOSPackages = (src) => {
271
+ const pkgList = [];
272
+ const allTypes = new Set();
273
+ if (TRIVY_BIN) {
274
+ let imageType = "image";
275
+ if (fs.existsSync(src)) {
276
+ imageType = "rootfs";
277
+ }
278
+ let tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "trivy-cdxgen-"));
279
+ const bomJsonFile = path.join(tempDir, "trivy-bom.json");
280
+ const args = [
281
+ imageType,
282
+ "--skip-update",
283
+ "--offline-scan",
284
+ "--format",
285
+ "cyclonedx",
286
+ "--output",
287
+ bomJsonFile
288
+ ];
289
+ if (!DEBUG_MODE) {
290
+ args.push("-q");
291
+ }
292
+ args.push(src);
293
+ if (DEBUG_MODE) {
294
+ console.log("Executing", TRIVY_BIN, args.join(" "));
295
+ }
296
+ let result = spawnSync(TRIVY_BIN, args, {
297
+ encoding: "utf-8"
298
+ });
299
+ if (result.status !== 0 || result.error) {
300
+ if (result.stdout || result.stderr) {
301
+ console.error(result.stdout, result.stderr);
302
+ }
303
+ }
304
+ if (fs.existsSync(bomJsonFile)) {
305
+ const tmpBom = JSON.parse(
306
+ fs.readFileSync(bomJsonFile, {
307
+ encoding: "utf-8"
308
+ })
309
+ );
310
+ // Clean up
311
+ if (tempDir && tempDir.startsWith(os.tmpdir())) {
312
+ if (DEBUG_MODE) {
313
+ console.log(`Cleaning up ${tempDir}`);
314
+ }
315
+ fs.rmSync(tempDir, { recursive: true, force: true });
316
+ }
317
+ if (tmpBom && tmpBom.components) {
318
+ for (const comp of tmpBom.components) {
319
+ if (comp.purl) {
320
+ // Retain go components alone from trivy
321
+ if (
322
+ comp.purl.startsWith("pkg:npm") ||
323
+ comp.purl.startsWith("pkg:maven") ||
324
+ comp.purl.startsWith("pkg:pypi") ||
325
+ comp.purl.startsWith("pkg:cargo") ||
326
+ comp.purl.startsWith("pkg:composer") ||
327
+ comp.purl.startsWith("pkg:gem") ||
328
+ comp.purl.startsWith("pkg:nuget") ||
329
+ comp.purl.startsWith("pkg:pub") ||
330
+ comp.purl.startsWith("pkg:hackage") ||
331
+ comp.purl.startsWith("pkg:hex") ||
332
+ comp.purl.startsWith("pkg:conan") ||
333
+ comp.purl.startsWith("pkg:clojars") ||
334
+ comp.purl.startsWith("pkg:github")
335
+ ) {
336
+ continue;
337
+ }
338
+ // Fix the group
339
+ let group = path.dirname(comp.name);
340
+ let name = path.basename(comp.name);
341
+ let purlObj = undefined;
342
+ let distro_codename = "";
343
+ if (group === ".") {
344
+ group = "";
345
+ }
346
+ comp.group = group;
347
+ comp.name = name;
348
+ if (group === "") {
349
+ try {
350
+ purlObj = PackageURL.fromString(comp.purl);
351
+ if (purlObj.namespace && purlObj.namespace !== "") {
352
+ group = purlObj.namespace;
353
+ comp.group = group;
354
+ purlObj.namespace = group;
355
+ }
356
+ // Bug fix for mageia and oracle linux
357
+ if (purlObj.type === "none") {
358
+ purlObj["type"] = "rpm";
359
+ purlObj["namespace"] = "";
360
+ comp.group = "";
361
+ distro_codename = undefined;
362
+ if (comp.purl && comp.purl.includes(".mga")) {
363
+ purlObj["namespace"] = "mageia";
364
+ comp.group = "mageia";
365
+ purlObj.qualifiers["distro"] = "mageia";
366
+ distro_codename = "mga";
367
+ } else if (comp.purl && comp.purl.includes(".el8")) {
368
+ purlObj.qualifiers["distro"] = "el8";
369
+ }
370
+ comp.purl = new PackageURL(
371
+ purlObj.type,
372
+ purlObj.namespace,
373
+ name,
374
+ purlObj.version,
375
+ purlObj.qualifiers,
376
+ purlObj.subpath
377
+ ).toString();
378
+ comp["bom-ref"] = comp.purl;
379
+ }
380
+ if (purlObj.type !== "none") {
381
+ allTypes.add(purlObj.type);
382
+ }
383
+ // Prefix distro codename for ubuntu
384
+ if (purlObj.qualifiers && purlObj.qualifiers.distro) {
385
+ allTypes.add(purlObj.qualifiers.distro);
386
+ if (OS_DISTRO_ALIAS[purlObj.qualifiers.distro]) {
387
+ distro_codename =
388
+ OS_DISTRO_ALIAS[purlObj.qualifiers.distro];
389
+ } else if (group === "alpine") {
390
+ const dtmpA = purlObj.qualifiers.distro.split(".");
391
+ if (dtmpA && dtmpA.length > 2) {
392
+ distro_codename = group + "-" + dtmpA[0] + "." + dtmpA[1];
393
+ }
394
+ } else if (group === "photon") {
395
+ const dtmpA = purlObj.qualifiers.distro.split("-");
396
+ if (dtmpA && dtmpA.length > 1) {
397
+ distro_codename = dtmpA[0];
398
+ }
399
+ } else if (group === "redhat") {
400
+ const dtmpA = purlObj.qualifiers.distro.split(".");
401
+ if (dtmpA && dtmpA.length > 1) {
402
+ distro_codename = dtmpA[0].replace(
403
+ "redhat",
404
+ "enterprise_linux"
405
+ );
406
+ }
407
+ }
408
+ if (distro_codename !== "") {
409
+ allTypes.add(distro_codename);
410
+ allTypes.add(purlObj.namespace);
411
+ purlObj.qualifiers["distro_name"] = distro_codename;
412
+ comp.purl = new PackageURL(
413
+ purlObj.type,
414
+ purlObj.namespace,
415
+ name,
416
+ purlObj.version,
417
+ purlObj.qualifiers,
418
+ purlObj.subpath
419
+ ).toString();
420
+ comp["bom-ref"] = comp.purl;
421
+ }
422
+ }
423
+ } catch (err) {
424
+ // continue regardless of error
425
+ }
426
+ }
427
+ if (
428
+ comp.licenses &&
429
+ Array.isArray(comp.licenses) &&
430
+ comp.licenses.length
431
+ ) {
432
+ comp.licenses = [comp.licenses[0]];
433
+ }
434
+ const compProperties = comp.properties;
435
+ let srcName = undefined;
436
+ let srcVersion = undefined;
437
+ if (compProperties && Array.isArray(compProperties)) {
438
+ for (const aprop of compProperties) {
439
+ if (aprop.name.endsWith("SrcName")) {
440
+ srcName = aprop.value;
441
+ }
442
+ if (aprop.name.endsWith("SrcVersion")) {
443
+ srcVersion = aprop.value;
444
+ }
445
+ }
446
+ }
447
+ delete comp.properties;
448
+ pkgList.push(comp);
449
+ // If there is a source package defined include it as well
450
+ if (srcName && srcVersion && srcName !== comp.name) {
451
+ let newComp = Object.assign({}, comp);
452
+ newComp.name = srcName;
453
+ newComp.version = srcVersion;
454
+ if (purlObj) {
455
+ newComp.purl = new PackageURL(
456
+ purlObj.type,
457
+ purlObj.namespace,
458
+ srcName,
459
+ srcVersion,
460
+ purlObj.qualifiers,
461
+ purlObj.subpath
462
+ ).toString();
463
+ }
464
+ newComp["bom-ref"] = newComp.purl;
465
+ pkgList.push(newComp);
466
+ }
467
+ }
468
+ }
469
+ }
470
+ return { osPackages: pkgList, allTypes: Array.from(allTypes) };
471
+ }
472
+ }
473
+ return { osPackages: pkgList, allTypes: Array.from(allTypes) };
474
+ };
475
+ exports.getOSPackages = getOSPackages;
476
+
477
+ const executeOsQuery = (query) => {
478
+ if (OSQUERY_BIN) {
479
+ if (!query.endsWith(";")) {
480
+ query = query + ";";
481
+ }
482
+ const args = ["--json", query];
483
+ if (DEBUG_MODE) {
484
+ console.log("Execuing", OSQUERY_BIN, args.join(" "));
485
+ }
486
+ let result = spawnSync(OSQUERY_BIN, args, {
487
+ encoding: "utf-8"
488
+ });
489
+ if (result.status !== 0 || result.error) {
490
+ if (DEBUG_MODE && result.error) {
491
+ console.error(result.stdout, result.stderr);
492
+ }
493
+ }
494
+ if (result) {
495
+ const stdout = result.stdout;
496
+ if (stdout) {
497
+ const cmdOutput = Buffer.from(stdout).toString();
498
+ if (cmdOutput !== "") {
499
+ return JSON.parse(cmdOutput);
500
+ }
501
+ return undefined;
502
+ }
503
+ }
504
+ }
505
+ return undefined;
506
+ };
507
+ exports.executeOsQuery = executeOsQuery;