@cyclonedx/cdxgen 9.6.1 → 9.7.1
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/README.md +18 -10
- package/bin/cdxgen.js +9 -4
- package/bin/repl.js +154 -26
- package/bin/verify.js +19 -0
- package/binary.js +41 -10
- package/data/queries-win.json +206 -0
- package/data/queries.json +160 -15
- package/display.js +58 -14
- package/docker.js +18 -1
- package/evinser.js +23 -32
- package/index.js +59 -14
- package/package.json +9 -6
- package/utils.js +222 -91
- package/utils.test.js +33 -4
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
cdxgen is a cli tool, library, [REPL](./ADVANCED.md) and server to create a valid and compliant [CycloneDX][cyclonedx-homepage] Software Bill-of-Materials (SBOM) containing an aggregate of all project dependencies for c/c++, node.js, php, python, ruby, rust, java, .Net, dart, haskell, elixir, and Go projects in JSON format. CycloneDX 1.5 is a lightweight SBOM specification that is easily created, human and machine-readable, and simple to parse.
|
|
6
6
|
|
|
7
|
-
When used with plugins, cdxgen could generate an
|
|
7
|
+
When used with plugins, cdxgen could generate an OBoM for Linux docker images and even VMs running Linux or Windows operating system. cdxgen also includes a tool called `evinse` that can generate component evidences and SaaSBoM for some languages.
|
|
8
8
|
|
|
9
9
|
NOTE:
|
|
10
10
|
|
|
@@ -90,6 +90,12 @@ sudo npm install -g @cyclonedx/cdxgen
|
|
|
90
90
|
sudo npm install -g @cyclonedx/cdxgen@8.6.0
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
+
If you are a [Homebrew](https://brew.sh/) user, you can also install [cdxgen](https://formulae.brew.sh/formula/cdxgen) via:
|
|
94
|
+
|
|
95
|
+
```shell
|
|
96
|
+
$ brew install cdxgen
|
|
97
|
+
```
|
|
98
|
+
|
|
93
99
|
Deno install is also supported.
|
|
94
100
|
|
|
95
101
|
```shell
|
|
@@ -127,9 +133,7 @@ Options:
|
|
|
127
133
|
-r, --recurse Recurse mode suitable for mono-repos. Defaults to
|
|
128
134
|
true. Pass --no-recurse to disable.
|
|
129
135
|
[boolean] [default: true]
|
|
130
|
-
-p, --print Print the SBoM as a table with tree.
|
|
131
|
-
true if output file is not specified with -o
|
|
132
|
-
[boolean]
|
|
136
|
+
-p, --print Print the SBoM as a table with tree. [boolean]
|
|
133
137
|
-c, --resolve-class Resolve class names for packages. jars only for n
|
|
134
138
|
ow. [boolean]
|
|
135
139
|
--deep Perform deep searches for components. Useful whil
|
|
@@ -163,8 +167,8 @@ Options:
|
|
|
163
167
|
[boolean] [default: true]
|
|
164
168
|
--spec-version CycloneDX Specification version to use. Defaults
|
|
165
169
|
to 1.5 [default: 1.5]
|
|
166
|
-
|
|
167
|
-
-
|
|
170
|
+
-h, --help Show help [boolean]
|
|
171
|
+
-v, --version Show version number [boolean]
|
|
168
172
|
```
|
|
169
173
|
|
|
170
174
|
All boolean arguments accepts `--no` prefix to toggle the behavior.
|
|
@@ -294,6 +298,8 @@ cdxgen can retain the dependency tree under the `dependencies` attribute for a s
|
|
|
294
298
|
| MVN_CMD | Set to override maven command |
|
|
295
299
|
| MVN_ARGS | Set to pass additional arguments such as profile or settings to maven |
|
|
296
300
|
| MAVEN_HOME | Specify maven home |
|
|
301
|
+
| MAVEN_CENTRAL_URL | Specify URL of Maven Central for metadata fetching (e.g. when private repo is used) |
|
|
302
|
+
| BAZEL_STRIP_MAVEN_PREFIX | Strip Maven group prefix (e.g. useful when private repo is used, defaults to `/maven2/`) |
|
|
297
303
|
| GRADLE_CACHE_DIR | Specify gradle cache directory. Useful for class name resolving |
|
|
298
304
|
| GRADLE_MULTI_PROJECT_MODE | Unused. Automatically handled |
|
|
299
305
|
| GRADLE_ARGS | Set to pass additional arguments such as profile or settings to gradle (all tasks). Eg: --configuration runtimeClassPath |
|
|
@@ -366,15 +372,17 @@ systemctl --user start podman.socket
|
|
|
366
372
|
podman system service -t 0 &
|
|
367
373
|
```
|
|
368
374
|
|
|
369
|
-
### Generate
|
|
375
|
+
### Generate OBoM for a live system
|
|
370
376
|
|
|
371
|
-
You can use
|
|
377
|
+
You can use the `obom` command to generate an OBoM for a live system or a VM for compliance and vulnerability management purposes. Windows and Linux operating systems are supported in this mode.
|
|
372
378
|
|
|
373
379
|
```shell
|
|
374
|
-
cdxgen -t os
|
|
380
|
+
# obom is an alias for cdxgen -t os
|
|
381
|
+
obom
|
|
382
|
+
# cdxgen -t os
|
|
375
383
|
```
|
|
376
384
|
|
|
377
|
-
This feature is powered by osquery which is [installed](https://github.com/cyclonedx/cdxgen-plugins-bin/blob/main/build.sh#L8) along with the binary plugins. cdxgen would opportunistically try to detect as many components, apps and extensions as possible using the [default queries](queries.json). The process would take several minutes and result in an SBoM file with thousands of components.
|
|
385
|
+
This feature is powered by osquery which is [installed](https://github.com/cyclonedx/cdxgen-plugins-bin/blob/main/build.sh#L8) along with the binary plugins. cdxgen would opportunistically try to detect as many components, apps and extensions as possible using the [default queries](queries.json). The process would take several minutes and result in an SBoM file with thousands of components of various types such as operating-system, device-drivers, files, and data.
|
|
378
386
|
|
|
379
387
|
## Generating SaaSBoM and component evidences
|
|
380
388
|
|
package/bin/cdxgen.js
CHANGED
|
@@ -41,8 +41,7 @@ const args = yargs(hideBin(process.argv))
|
|
|
41
41
|
.option("print", {
|
|
42
42
|
alias: "p",
|
|
43
43
|
type: "boolean",
|
|
44
|
-
description:
|
|
45
|
-
"Print the SBoM as a table with tree. Defaults to true if output file is not specified with -o"
|
|
44
|
+
description: "Print the SBoM as a table with tree."
|
|
46
45
|
})
|
|
47
46
|
.option("resolve-class", {
|
|
48
47
|
alias: "c",
|
|
@@ -122,7 +121,9 @@ const args = yargs(hideBin(process.argv))
|
|
|
122
121
|
})
|
|
123
122
|
.scriptName("cdxgen")
|
|
124
123
|
.version()
|
|
125
|
-
.
|
|
124
|
+
.alias("v", "version")
|
|
125
|
+
.help("h")
|
|
126
|
+
.alias("h", "help").argv;
|
|
126
127
|
|
|
127
128
|
if (args.version) {
|
|
128
129
|
const packageJsonAsString = fs.readFileSync(
|
|
@@ -157,6 +158,11 @@ if (args.serverUrl || args.apiKey) {
|
|
|
157
158
|
args.specVersion = 1.4;
|
|
158
159
|
}
|
|
159
160
|
|
|
161
|
+
// Support for obom aliases
|
|
162
|
+
if (process.argv[1].includes("obom") && !args.type) {
|
|
163
|
+
args.type = "os";
|
|
164
|
+
}
|
|
165
|
+
|
|
160
166
|
/**
|
|
161
167
|
* projectType: python, nodejs, java, golang
|
|
162
168
|
* multiProject: Boolean to indicate monorepo or multi-module projects
|
|
@@ -229,7 +235,6 @@ const checkPermissions = (filePath) => {
|
|
|
229
235
|
const bomNSData = (await createBom(filePath, options)) || {};
|
|
230
236
|
if (!args.output) {
|
|
231
237
|
args.output = "bom.json";
|
|
232
|
-
args.print = true;
|
|
233
238
|
}
|
|
234
239
|
if (
|
|
235
240
|
args.output &&
|
package/bin/repl.js
CHANGED
|
@@ -12,6 +12,7 @@ import { validateBom } from "../validator.js";
|
|
|
12
12
|
import {
|
|
13
13
|
printCallStack,
|
|
14
14
|
printOccurrences,
|
|
15
|
+
printOSTable,
|
|
15
16
|
printTable,
|
|
16
17
|
printDependencyTree,
|
|
17
18
|
printServices
|
|
@@ -32,8 +33,8 @@ process.env.NODE_NO_READLINE = 1;
|
|
|
32
33
|
const cdxArt = `
|
|
33
34
|
██████╗██████╗ ██╗ ██╗
|
|
34
35
|
██╔════╝██╔══██╗╚██╗██╔╝
|
|
35
|
-
██║ ██║ ██║ ╚███╔╝
|
|
36
|
-
██║ ██║ ██║ ██╔██╗
|
|
36
|
+
██║ ██║ ██║ ╚███╔╝
|
|
37
|
+
██║ ██║ ██║ ██╔██╗
|
|
37
38
|
╚██████╗██████╔╝██╔╝ ██╗
|
|
38
39
|
╚═════╝╚═════╝ ╚═╝ ╚═╝
|
|
39
40
|
`;
|
|
@@ -109,16 +110,16 @@ cdxgenRepl.defineCommand("create", {
|
|
|
109
110
|
});
|
|
110
111
|
if (bomNSData) {
|
|
111
112
|
sbom = bomNSData.bomJson;
|
|
112
|
-
console.log("✅
|
|
113
|
-
console.log("💭 Type .print to view the
|
|
113
|
+
console.log("✅ BoM imported successfully.");
|
|
114
|
+
console.log("💭 Type .print to view the BoM as a table");
|
|
114
115
|
} else {
|
|
115
|
-
console.log("
|
|
116
|
+
console.log("BoM was not generated successfully");
|
|
116
117
|
}
|
|
117
118
|
this.displayPrompt();
|
|
118
119
|
}
|
|
119
120
|
});
|
|
120
121
|
cdxgenRepl.defineCommand("import", {
|
|
121
|
-
help: "import an existing
|
|
122
|
+
help: "import an existing BoM",
|
|
122
123
|
action(sbomOrPath) {
|
|
123
124
|
this.clearBufferedCommand();
|
|
124
125
|
importSbom(sbomOrPath);
|
|
@@ -138,14 +139,14 @@ cdxgenRepl.defineCommand("sbom", {
|
|
|
138
139
|
console.log(sbom);
|
|
139
140
|
} else {
|
|
140
141
|
console.log(
|
|
141
|
-
"⚠ No
|
|
142
|
+
"⚠ No BoM is loaded. Use .import command to import an existing BoM"
|
|
142
143
|
);
|
|
143
144
|
}
|
|
144
145
|
this.displayPrompt();
|
|
145
146
|
}
|
|
146
147
|
});
|
|
147
148
|
cdxgenRepl.defineCommand("search", {
|
|
148
|
-
help: "search the current
|
|
149
|
+
help: "search the current bom. performs case insensitive search on various attributes.",
|
|
149
150
|
async action(searchStr) {
|
|
150
151
|
if (sbom) {
|
|
151
152
|
if (searchStr) {
|
|
@@ -170,14 +171,14 @@ cdxgenRepl.defineCommand("search", {
|
|
|
170
171
|
}
|
|
171
172
|
} else {
|
|
172
173
|
console.log(
|
|
173
|
-
"⚠ No
|
|
174
|
+
"⚠ No BoM is loaded. Use .import command to import an existing BoM"
|
|
174
175
|
);
|
|
175
176
|
}
|
|
176
177
|
this.displayPrompt();
|
|
177
178
|
}
|
|
178
179
|
});
|
|
179
180
|
cdxgenRepl.defineCommand("sort", {
|
|
180
|
-
help: "sort the current
|
|
181
|
+
help: "sort the current bom based on the attribute",
|
|
181
182
|
async action(sortStr) {
|
|
182
183
|
if (sbom) {
|
|
183
184
|
if (sortStr) {
|
|
@@ -204,14 +205,14 @@ cdxgenRepl.defineCommand("sort", {
|
|
|
204
205
|
}
|
|
205
206
|
} else {
|
|
206
207
|
console.log(
|
|
207
|
-
"⚠ No
|
|
208
|
+
"⚠ No BoM is loaded. Use .import command to import an existing BoM"
|
|
208
209
|
);
|
|
209
210
|
}
|
|
210
211
|
this.displayPrompt();
|
|
211
212
|
}
|
|
212
213
|
});
|
|
213
214
|
cdxgenRepl.defineCommand("query", {
|
|
214
|
-
help: "query the current
|
|
215
|
+
help: "query the current bom using jsonata expression",
|
|
215
216
|
async action(querySpec) {
|
|
216
217
|
if (sbom) {
|
|
217
218
|
if (querySpec) {
|
|
@@ -228,20 +229,20 @@ cdxgenRepl.defineCommand("query", {
|
|
|
228
229
|
}
|
|
229
230
|
} else {
|
|
230
231
|
console.log(
|
|
231
|
-
"⚠ No
|
|
232
|
+
"⚠ No BoM is loaded. Use .import command to import an existing BoM"
|
|
232
233
|
);
|
|
233
234
|
}
|
|
234
235
|
this.displayPrompt();
|
|
235
236
|
}
|
|
236
237
|
});
|
|
237
238
|
cdxgenRepl.defineCommand("print", {
|
|
238
|
-
help: "print the current
|
|
239
|
+
help: "print the current bom as a table",
|
|
239
240
|
action() {
|
|
240
241
|
if (sbom) {
|
|
241
242
|
printTable(sbom);
|
|
242
243
|
} else {
|
|
243
244
|
console.log(
|
|
244
|
-
"⚠ No
|
|
245
|
+
"⚠ No BoM is loaded. Use .import command to import an existing BoM"
|
|
245
246
|
);
|
|
246
247
|
}
|
|
247
248
|
this.displayPrompt();
|
|
@@ -254,14 +255,14 @@ cdxgenRepl.defineCommand("tree", {
|
|
|
254
255
|
printDependencyTree(sbom);
|
|
255
256
|
} else {
|
|
256
257
|
console.log(
|
|
257
|
-
"⚠ No
|
|
258
|
+
"⚠ No BoM is loaded. Use .import command to import an existing BoM"
|
|
258
259
|
);
|
|
259
260
|
}
|
|
260
261
|
this.displayPrompt();
|
|
261
262
|
}
|
|
262
263
|
});
|
|
263
264
|
cdxgenRepl.defineCommand("validate", {
|
|
264
|
-
help: "validate the
|
|
265
|
+
help: "validate the bom using jsonschema",
|
|
265
266
|
action() {
|
|
266
267
|
if (sbom) {
|
|
267
268
|
const result = validateBom(sbom);
|
|
@@ -270,31 +271,31 @@ cdxgenRepl.defineCommand("validate", {
|
|
|
270
271
|
}
|
|
271
272
|
} else {
|
|
272
273
|
console.log(
|
|
273
|
-
"⚠ No
|
|
274
|
+
"⚠ No BoM is loaded. Use .import command to import an existing BoM"
|
|
274
275
|
);
|
|
275
276
|
}
|
|
276
277
|
this.displayPrompt();
|
|
277
278
|
}
|
|
278
279
|
});
|
|
279
280
|
cdxgenRepl.defineCommand("save", {
|
|
280
|
-
help: "save the
|
|
281
|
+
help: "save the bom to a new file",
|
|
281
282
|
action(saveToFile) {
|
|
282
283
|
if (sbom) {
|
|
283
284
|
if (!saveToFile) {
|
|
284
285
|
saveToFile = "bom.json";
|
|
285
286
|
}
|
|
286
287
|
fs.writeFileSync(saveToFile, JSON.stringify(sbom, null, 2));
|
|
287
|
-
console.log(`
|
|
288
|
+
console.log(`BoM saved successfully to ${saveToFile}`);
|
|
288
289
|
} else {
|
|
289
290
|
console.log(
|
|
290
|
-
"⚠ No
|
|
291
|
+
"⚠ No BoM is loaded. Use .import command to import an existing BoM"
|
|
291
292
|
);
|
|
292
293
|
}
|
|
293
294
|
this.displayPrompt();
|
|
294
295
|
}
|
|
295
296
|
});
|
|
296
297
|
cdxgenRepl.defineCommand("update", {
|
|
297
|
-
help: "update the
|
|
298
|
+
help: "update the bom components based on the given query",
|
|
298
299
|
async action(updateSpec) {
|
|
299
300
|
if (sbom) {
|
|
300
301
|
if (!updateSpec) {
|
|
@@ -312,10 +313,10 @@ cdxgenRepl.defineCommand("update", {
|
|
|
312
313
|
if (newSbom && newSbom.components.length <= sbom.components.length) {
|
|
313
314
|
sbom = newSbom;
|
|
314
315
|
}
|
|
315
|
-
console.log("
|
|
316
|
+
console.log("BoM updated successfully.");
|
|
316
317
|
} else {
|
|
317
318
|
console.log(
|
|
318
|
-
"⚠ No
|
|
319
|
+
"⚠ No BoM is loaded. Use .import command to import an existing BoM"
|
|
319
320
|
);
|
|
320
321
|
}
|
|
321
322
|
this.displayPrompt();
|
|
@@ -332,7 +333,7 @@ cdxgenRepl.defineCommand("occurrences", {
|
|
|
332
333
|
let components = await expression.evaluate(sbom);
|
|
333
334
|
if (!components) {
|
|
334
335
|
console.log(
|
|
335
|
-
"No results found. Use evinse command to generate an
|
|
336
|
+
"No results found. Use evinse command to generate an BoM with evidence."
|
|
336
337
|
);
|
|
337
338
|
} else {
|
|
338
339
|
if (!Array.isArray(components)) {
|
|
@@ -345,7 +346,7 @@ cdxgenRepl.defineCommand("occurrences", {
|
|
|
345
346
|
}
|
|
346
347
|
} else {
|
|
347
348
|
console.log(
|
|
348
|
-
"⚠ No
|
|
349
|
+
"⚠ No BoM is loaded. Use .import command to import an evinse BoM"
|
|
349
350
|
);
|
|
350
351
|
}
|
|
351
352
|
this.displayPrompt();
|
|
@@ -425,3 +426,130 @@ cdxgenRepl.defineCommand("services", {
|
|
|
425
426
|
this.displayPrompt();
|
|
426
427
|
}
|
|
427
428
|
});
|
|
429
|
+
cdxgenRepl.defineCommand("osinfocategories", {
|
|
430
|
+
help: "view the category names for the OS info from the obom",
|
|
431
|
+
async action() {
|
|
432
|
+
if (sbom) {
|
|
433
|
+
try {
|
|
434
|
+
const expression = jsonata(
|
|
435
|
+
'$distinct(components.properties[name="cdx:osquery:category"].value)'
|
|
436
|
+
);
|
|
437
|
+
let catgories = await expression.evaluate(sbom);
|
|
438
|
+
if (!catgories) {
|
|
439
|
+
console.log(
|
|
440
|
+
"Unable to retrieve the os info categories. Only OBoMs generated by cdxgen are supported by this tool."
|
|
441
|
+
);
|
|
442
|
+
} else {
|
|
443
|
+
console.log(catgories.join("\n"));
|
|
444
|
+
}
|
|
445
|
+
} catch (e) {
|
|
446
|
+
console.log(e);
|
|
447
|
+
}
|
|
448
|
+
} else {
|
|
449
|
+
console.log(
|
|
450
|
+
"⚠ No OBoM is loaded. Use .import command to import an OBoM"
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
this.displayPrompt();
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
// Let's dynamically define more commands from the queries
|
|
458
|
+
[
|
|
459
|
+
"apt_sources",
|
|
460
|
+
"behavioral_reverse_shell",
|
|
461
|
+
"certificates",
|
|
462
|
+
"chrome_extensions",
|
|
463
|
+
"crontab_snapshot",
|
|
464
|
+
"deb_packages",
|
|
465
|
+
"docker_container_ports",
|
|
466
|
+
"docker_containers",
|
|
467
|
+
"docker_networks",
|
|
468
|
+
"docker_volumes",
|
|
469
|
+
"etc_hosts",
|
|
470
|
+
"firefox_addons",
|
|
471
|
+
"homebrew_packages",
|
|
472
|
+
"installed_applications",
|
|
473
|
+
"interface_addresses",
|
|
474
|
+
"kernel_info",
|
|
475
|
+
"kernel_integrity",
|
|
476
|
+
"kernel_modules",
|
|
477
|
+
"ld_preload",
|
|
478
|
+
"listening_ports",
|
|
479
|
+
"os_version",
|
|
480
|
+
"pipes",
|
|
481
|
+
"pipes_snapshot",
|
|
482
|
+
"portage_packages",
|
|
483
|
+
"process_events",
|
|
484
|
+
"processes",
|
|
485
|
+
"python_packages",
|
|
486
|
+
"rpm_packages",
|
|
487
|
+
"scheduled_tasks",
|
|
488
|
+
"services_snapshot",
|
|
489
|
+
"startup_items",
|
|
490
|
+
"system_info_snapshot",
|
|
491
|
+
"windows_drivers",
|
|
492
|
+
"windows_patches",
|
|
493
|
+
"windows_programs",
|
|
494
|
+
"windows_shared_resources",
|
|
495
|
+
"yum_sources",
|
|
496
|
+
"appcompat_shims",
|
|
497
|
+
"atom_packages",
|
|
498
|
+
"browser_plugins",
|
|
499
|
+
"certificates",
|
|
500
|
+
"chocolatey_packages",
|
|
501
|
+
"chrome_extensions",
|
|
502
|
+
"etc_hosts",
|
|
503
|
+
"firefox_addons",
|
|
504
|
+
"ie_extensions",
|
|
505
|
+
"kernel_info",
|
|
506
|
+
"npm_packages",
|
|
507
|
+
"opera_extensions",
|
|
508
|
+
"pipes_snapshot",
|
|
509
|
+
"process_open_sockets",
|
|
510
|
+
"safari_extensions",
|
|
511
|
+
"scheduled_tasks",
|
|
512
|
+
"services_snapshot",
|
|
513
|
+
"startup_items",
|
|
514
|
+
"routes",
|
|
515
|
+
"system_info_snapshot",
|
|
516
|
+
"win_version",
|
|
517
|
+
"windows_firewall_rules",
|
|
518
|
+
"windows_optional_features",
|
|
519
|
+
"windows_programs",
|
|
520
|
+
"windows_shared_resources",
|
|
521
|
+
"windows_update_history",
|
|
522
|
+
"wmi_cli_event_consumers",
|
|
523
|
+
"wmi_cli_event_consumers_snapshot",
|
|
524
|
+
"wmi_event_filters",
|
|
525
|
+
"wmi_filter_consumer_binding"
|
|
526
|
+
].forEach((c) => {
|
|
527
|
+
cdxgenRepl.defineCommand(c, {
|
|
528
|
+
help: `query the ${c} category from the OS info`,
|
|
529
|
+
async action() {
|
|
530
|
+
if (sbom) {
|
|
531
|
+
try {
|
|
532
|
+
const expression = jsonata(
|
|
533
|
+
`components[properties[name="cdx:osquery:category" and value="${c}"]]`
|
|
534
|
+
);
|
|
535
|
+
let components = await expression.evaluate(sbom);
|
|
536
|
+
if (!components) {
|
|
537
|
+
console.log("No results found.");
|
|
538
|
+
} else {
|
|
539
|
+
if (!Array.isArray(components)) {
|
|
540
|
+
components = [components];
|
|
541
|
+
}
|
|
542
|
+
printOSTable({ components });
|
|
543
|
+
}
|
|
544
|
+
} catch (e) {
|
|
545
|
+
console.log(e);
|
|
546
|
+
}
|
|
547
|
+
} else {
|
|
548
|
+
console.log(
|
|
549
|
+
"⚠ No OBoM is loaded. Use .import command to import an OBoM"
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
this.displayPrompt();
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
});
|
package/bin/verify.js
CHANGED
|
@@ -40,6 +40,25 @@ if (args.version) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const bomJson = JSON.parse(fs.readFileSync(args.input, "utf8"));
|
|
43
|
+
let hasInvalidComp = false;
|
|
44
|
+
// Validate any component signature
|
|
45
|
+
for (const comp of bomJson.components) {
|
|
46
|
+
if (comp.signature) {
|
|
47
|
+
const compSignature = comp.signature.value;
|
|
48
|
+
const validationResult = jws.verify(
|
|
49
|
+
compSignature,
|
|
50
|
+
comp.signature.algorithm,
|
|
51
|
+
fs.readFileSync(args.publicKey, "utf8")
|
|
52
|
+
);
|
|
53
|
+
if (!validationResult) {
|
|
54
|
+
console.log(`${comp["bom-ref"]} signature is invalid!`);
|
|
55
|
+
hasInvalidComp = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (hasInvalidComp) {
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
43
62
|
const bomSignature =
|
|
44
63
|
bomJson.signature && bomJson.signature.value
|
|
45
64
|
? bomJson.signature.value
|
package/binary.js
CHANGED
|
@@ -17,6 +17,7 @@ const isWin = _platform() === "win32";
|
|
|
17
17
|
|
|
18
18
|
let platform = _platform();
|
|
19
19
|
let extn = "";
|
|
20
|
+
let pluginsBinSuffix = "";
|
|
20
21
|
if (platform == "win32") {
|
|
21
22
|
platform = "windows";
|
|
22
23
|
extn = ".exe";
|
|
@@ -30,6 +31,13 @@ switch (arch) {
|
|
|
30
31
|
case "x64":
|
|
31
32
|
arch = "amd64";
|
|
32
33
|
break;
|
|
34
|
+
case "arm64":
|
|
35
|
+
pluginsBinSuffix = "-arm64";
|
|
36
|
+
break;
|
|
37
|
+
case "ppc64":
|
|
38
|
+
arch = "ppc64le";
|
|
39
|
+
pluginsBinSuffix = "-ppc64";
|
|
40
|
+
break;
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
// Retrieve the cdxgen plugins directory
|
|
@@ -46,14 +54,20 @@ if (
|
|
|
46
54
|
if (
|
|
47
55
|
!CDXGEN_PLUGINS_DIR &&
|
|
48
56
|
existsSync(
|
|
49
|
-
join(
|
|
57
|
+
join(
|
|
58
|
+
dirName,
|
|
59
|
+
"node_modules",
|
|
60
|
+
"@cyclonedx",
|
|
61
|
+
"cdxgen-plugins-bin" + pluginsBinSuffix,
|
|
62
|
+
"plugins"
|
|
63
|
+
)
|
|
50
64
|
) &&
|
|
51
65
|
existsSync(
|
|
52
66
|
join(
|
|
53
67
|
dirName,
|
|
54
68
|
"node_modules",
|
|
55
69
|
"@cyclonedx",
|
|
56
|
-
"cdxgen-plugins-bin",
|
|
70
|
+
"cdxgen-plugins-bin" + pluginsBinSuffix,
|
|
57
71
|
"plugins",
|
|
58
72
|
"goversion"
|
|
59
73
|
)
|
|
@@ -63,7 +77,7 @@ if (
|
|
|
63
77
|
dirName,
|
|
64
78
|
"node_modules",
|
|
65
79
|
"@cyclonedx",
|
|
66
|
-
"cdxgen-plugins-bin",
|
|
80
|
+
"cdxgen-plugins-bin" + pluginsBinSuffix,
|
|
67
81
|
"plugins"
|
|
68
82
|
);
|
|
69
83
|
}
|
|
@@ -88,7 +102,7 @@ if (!CDXGEN_PLUGINS_DIR) {
|
|
|
88
102
|
const globalPlugins = join(
|
|
89
103
|
globalNodePath,
|
|
90
104
|
"@cyclonedx",
|
|
91
|
-
"cdxgen-plugins-bin",
|
|
105
|
+
"cdxgen-plugins-bin" + pluginsBinSuffix,
|
|
92
106
|
"plugins"
|
|
93
107
|
);
|
|
94
108
|
if (existsSync(globalPlugins)) {
|
|
@@ -323,15 +337,21 @@ export const getOSPackages = (src) => {
|
|
|
323
337
|
}
|
|
324
338
|
}
|
|
325
339
|
const osReleaseData = {};
|
|
326
|
-
|
|
327
|
-
|
|
340
|
+
let osReleaseFile = undefined;
|
|
341
|
+
// Let's try to read the os-release file from various locations
|
|
342
|
+
if (existsSync(join(src, "etc", "os-release"))) {
|
|
343
|
+
osReleaseFile = join(src, "etc", "os-release");
|
|
344
|
+
} else if (existsSync(join(src, "usr", "lib", "os-release"))) {
|
|
345
|
+
osReleaseFile = join(src, "usr", "lib", "os-release");
|
|
346
|
+
}
|
|
347
|
+
if (osReleaseFile) {
|
|
328
348
|
const osReleaseInfo = readFileSync(
|
|
329
349
|
join(src, "usr", "lib", "os-release"),
|
|
330
350
|
"utf-8"
|
|
331
351
|
);
|
|
332
352
|
if (osReleaseInfo) {
|
|
333
353
|
osReleaseInfo.split("\n").forEach((l) => {
|
|
334
|
-
if (l.includes("=")) {
|
|
354
|
+
if (!l.startsWith("#") && l.includes("=")) {
|
|
335
355
|
const tmpA = l.split("=");
|
|
336
356
|
osReleaseData[tmpA[0]] = tmpA[1].replace(/"/g, "");
|
|
337
357
|
}
|
|
@@ -592,10 +612,11 @@ export const executeOsQuery = (query) => {
|
|
|
592
612
|
}
|
|
593
613
|
const args = ["--json", query];
|
|
594
614
|
if (DEBUG_MODE) {
|
|
595
|
-
console.log("
|
|
615
|
+
console.log("Executing", OSQUERY_BIN, args.join(" "));
|
|
596
616
|
}
|
|
597
617
|
const result = spawnSync(OSQUERY_BIN, args, {
|
|
598
|
-
encoding: "utf-8"
|
|
618
|
+
encoding: "utf-8",
|
|
619
|
+
maxBuffer: 50 * 1024 * 1024
|
|
599
620
|
});
|
|
600
621
|
if (result.status !== 0 || result.error) {
|
|
601
622
|
if (DEBUG_MODE && result.error) {
|
|
@@ -607,7 +628,17 @@ export const executeOsQuery = (query) => {
|
|
|
607
628
|
if (stdout) {
|
|
608
629
|
const cmdOutput = Buffer.from(stdout).toString();
|
|
609
630
|
if (cmdOutput !== "") {
|
|
610
|
-
|
|
631
|
+
try {
|
|
632
|
+
return JSON.parse(cmdOutput);
|
|
633
|
+
} catch (err) {
|
|
634
|
+
// ignore
|
|
635
|
+
if (DEBUG_MODE) {
|
|
636
|
+
console.log("Unable to parse the output from query", query);
|
|
637
|
+
console.log(
|
|
638
|
+
"This could be due to the amount of data returned or the query being invalid for the given platform."
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
611
642
|
}
|
|
612
643
|
return undefined;
|
|
613
644
|
}
|