@cyclonedx/cdxgen 9.9.1 → 9.9.2
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 +5 -1
- package/bin/cdxgen.js +67 -21
- package/data/wrapdb-releases.json +503 -206
- package/index.js +41 -9
- package/package.json +2 -2
- package/server.js +1 -1
- package/utils.js +135 -13
- package/utils.test.js +23 -3
package/README.md
CHANGED
|
@@ -181,6 +181,10 @@ Options:
|
|
|
181
181
|
--author The person(s) who created the BOM. Set this value
|
|
182
182
|
if you're intending the modify the BOM and claim
|
|
183
183
|
authorship.[array] [default: "OWASP Foundation"]
|
|
184
|
+
--profile BOM profile to use for generation. Default generi
|
|
185
|
+
c.
|
|
186
|
+
[choices: "appsec", "research", "operational", "threat-modeling", "license-com
|
|
187
|
+
pliance", "generic"] [default: "generic"]
|
|
184
188
|
--auto-compositions Automatically set compositions when the BOM was f
|
|
185
189
|
iltered. Defaults to true
|
|
186
190
|
[boolean] [default: true]
|
|
@@ -373,7 +377,7 @@ cdxgen can retain the dependency tree under the `dependencies` attribute for a s
|
|
|
373
377
|
| SBOM_SIGN_ALGORITHM | Signature algorithm. Some valid values are RS256, RS384, RS512, PS256, PS384, PS512, ES256 etc |
|
|
374
378
|
| SBOM_SIGN_PRIVATE_KEY | Private key to use for signing |
|
|
375
379
|
| SBOM_SIGN_PUBLIC_KEY | Optional. Public key to include in the SBOM signature |
|
|
376
|
-
| CDX_MAVEN_PLUGIN | CycloneDX Maven plugin to use. Default "org.cyclonedx:cyclonedx-maven-plugin:2.7.
|
|
380
|
+
| CDX_MAVEN_PLUGIN | CycloneDX Maven plugin to use. Default "org.cyclonedx:cyclonedx-maven-plugin:2.7.10" |
|
|
377
381
|
| CDX_MAVEN_GOAL | CycloneDX Maven plugin goal to use. Default makeAggregateBom. Other options: makeBom, makePackageBom |
|
|
378
382
|
| CDX_MAVEN_INCLUDE_TEST_SCOPE | Whether test scoped dependencies should be included from Maven projects, Default: true |
|
|
379
383
|
| ASTGEN_IGNORE_DIRS | Comma separated list of directories to ignore while analyzing using babel. The environment variable is also used by atom and astgen. |
|
package/bin/cdxgen.js
CHANGED
|
@@ -21,7 +21,6 @@ import {
|
|
|
21
21
|
import { findUpSync } from "find-up";
|
|
22
22
|
import { load as _load } from "js-yaml";
|
|
23
23
|
import { postProcess } from "../postgen.js";
|
|
24
|
-
import { analyzeProject, createEvinseFile, prepareDB } from "../evinser.js";
|
|
25
24
|
import { ATOM_DB } from "../utils.js";
|
|
26
25
|
|
|
27
26
|
// Support for config files
|
|
@@ -204,6 +203,18 @@ const args = yargs(hideBin(process.argv))
|
|
|
204
203
|
"The person(s) who created the BOM. Set this value if you're intending the modify the BOM and claim authorship.",
|
|
205
204
|
default: "OWASP Foundation"
|
|
206
205
|
})
|
|
206
|
+
.option("profile", {
|
|
207
|
+
description: "BOM profile to use for generation. Default generic.",
|
|
208
|
+
default: "generic",
|
|
209
|
+
choices: [
|
|
210
|
+
"appsec",
|
|
211
|
+
"research",
|
|
212
|
+
"operational",
|
|
213
|
+
"threat-modeling",
|
|
214
|
+
"license-compliance",
|
|
215
|
+
"generic"
|
|
216
|
+
]
|
|
217
|
+
})
|
|
207
218
|
.completion("completion", "Generate bash/zsh completion")
|
|
208
219
|
.array("filter")
|
|
209
220
|
.array("only")
|
|
@@ -259,6 +270,32 @@ if (process.argv[1].includes("obom") && !args.type) {
|
|
|
259
270
|
args.type = "os";
|
|
260
271
|
}
|
|
261
272
|
|
|
273
|
+
const applyProfile = (options) => {
|
|
274
|
+
switch (options.profile) {
|
|
275
|
+
case "appsec":
|
|
276
|
+
options.deep = true;
|
|
277
|
+
break;
|
|
278
|
+
case "research":
|
|
279
|
+
options.deep = true;
|
|
280
|
+
options.evidence = true;
|
|
281
|
+
process.env.CDX_MAVEN_INCLUDE_TEST_SCOPE = true;
|
|
282
|
+
process.env.ASTGEN_IGNORE_DIRS = "";
|
|
283
|
+
process.env.ASTGEN_IGNORE_FILE_PATTERN = "";
|
|
284
|
+
break;
|
|
285
|
+
case "operational":
|
|
286
|
+
options.projectType = options.projectType || "os";
|
|
287
|
+
break;
|
|
288
|
+
case "threat-modeling": // unused
|
|
289
|
+
break;
|
|
290
|
+
case "license-compliance":
|
|
291
|
+
process.env.FETCH_LICENSE = true;
|
|
292
|
+
break;
|
|
293
|
+
default:
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
return options;
|
|
297
|
+
};
|
|
298
|
+
|
|
262
299
|
/**
|
|
263
300
|
* Command line options
|
|
264
301
|
*/
|
|
@@ -266,8 +303,10 @@ const options = Object.assign({}, args, {
|
|
|
266
303
|
projectType: args.type,
|
|
267
304
|
multiProject: args.recurse,
|
|
268
305
|
noBabel: args.noBabel || args.babel === false,
|
|
269
|
-
project: args.projectId
|
|
306
|
+
project: args.projectId,
|
|
307
|
+
deep: args.deep || args.evidence
|
|
270
308
|
});
|
|
309
|
+
applyProfile(options);
|
|
271
310
|
|
|
272
311
|
/**
|
|
273
312
|
* Check for node >= 20 permissions
|
|
@@ -306,7 +345,7 @@ const checkPermissions = (filePath) => {
|
|
|
306
345
|
*/
|
|
307
346
|
(async () => {
|
|
308
347
|
// Start SBOM server
|
|
309
|
-
if (
|
|
348
|
+
if (options.server) {
|
|
310
349
|
const serverModule = await import("../server.js");
|
|
311
350
|
return serverModule.start(options);
|
|
312
351
|
}
|
|
@@ -323,15 +362,15 @@ const checkPermissions = (filePath) => {
|
|
|
323
362
|
bomNSData = postProcess(bomNSData, options);
|
|
324
363
|
}
|
|
325
364
|
if (
|
|
326
|
-
|
|
327
|
-
(typeof
|
|
365
|
+
options.output &&
|
|
366
|
+
(typeof options.output === "string" || options.output instanceof String)
|
|
328
367
|
) {
|
|
329
368
|
if (bomNSData.bomXmlFiles) {
|
|
330
369
|
console.log("BOM files produced:", bomNSData.bomXmlFiles);
|
|
331
370
|
} else {
|
|
332
|
-
const jsonFile =
|
|
371
|
+
const jsonFile = options.output.replace(".xml", ".json");
|
|
333
372
|
// Create bom json file
|
|
334
|
-
if (!
|
|
373
|
+
if (!options.output.endsWith(".xml") && bomNSData.bomJson) {
|
|
335
374
|
let jsonPayload = undefined;
|
|
336
375
|
if (
|
|
337
376
|
typeof bomNSData.bomJson === "string" ||
|
|
@@ -345,7 +384,7 @@ const checkPermissions = (filePath) => {
|
|
|
345
384
|
}
|
|
346
385
|
if (
|
|
347
386
|
jsonPayload &&
|
|
348
|
-
(
|
|
387
|
+
(options.generateKeyAndSign ||
|
|
349
388
|
(process.env.SBOM_SIGN_ALGORITHM &&
|
|
350
389
|
process.env.SBOM_SIGN_ALGORITHM !== "none" &&
|
|
351
390
|
process.env.SBOM_SIGN_PRIVATE_KEY &&
|
|
@@ -358,7 +397,7 @@ const checkPermissions = (filePath) => {
|
|
|
358
397
|
let privateKeyToUse = undefined;
|
|
359
398
|
let jwkPublicKey = undefined;
|
|
360
399
|
let publicKeyFile = undefined;
|
|
361
|
-
if (
|
|
400
|
+
if (options.generateKeyAndSign) {
|
|
362
401
|
const jdirName = dirname(jsonFile);
|
|
363
402
|
publicKeyFile = join(jdirName, "public.key");
|
|
364
403
|
const privateKeyFile = join(jdirName, "private.key");
|
|
@@ -468,8 +507,8 @@ const checkPermissions = (filePath) => {
|
|
|
468
507
|
}
|
|
469
508
|
}
|
|
470
509
|
// Create bom xml file
|
|
471
|
-
if (
|
|
472
|
-
fs.writeFileSync(
|
|
510
|
+
if (options.output.endsWith(".xml") && bomNSData.bomXml) {
|
|
511
|
+
fs.writeFileSync(options.output, bomNSData.bomXml);
|
|
473
512
|
}
|
|
474
513
|
//
|
|
475
514
|
if (bomNSData.nsMapping && Object.keys(bomNSData.nsMapping).length) {
|
|
@@ -478,7 +517,7 @@ const checkPermissions = (filePath) => {
|
|
|
478
517
|
console.log("Namespace mapping file written to", nsFile);
|
|
479
518
|
}
|
|
480
519
|
}
|
|
481
|
-
} else if (!
|
|
520
|
+
} else if (!options.print) {
|
|
482
521
|
if (bomNSData.bomJson) {
|
|
483
522
|
console.log(JSON.stringify(bomNSData.bomJson, null, 2));
|
|
484
523
|
} else if (bomNSData.bomXml) {
|
|
@@ -489,7 +528,8 @@ const checkPermissions = (filePath) => {
|
|
|
489
528
|
}
|
|
490
529
|
}
|
|
491
530
|
// Evidence generation
|
|
492
|
-
if (
|
|
531
|
+
if (options.evidence) {
|
|
532
|
+
const evinserModule = await import("../evinser.js");
|
|
493
533
|
const evinseOptions = {
|
|
494
534
|
_: args._,
|
|
495
535
|
input: options.output,
|
|
@@ -503,12 +543,18 @@ const checkPermissions = (filePath) => {
|
|
|
503
543
|
dataFlowSlicesFile: options.dataFlowSlicesFile,
|
|
504
544
|
reachablesSlicesFile: options.reachablesSlicesFile
|
|
505
545
|
};
|
|
506
|
-
const dbObjMap = await prepareDB(evinseOptions);
|
|
546
|
+
const dbObjMap = await evinserModule.prepareDB(evinseOptions);
|
|
507
547
|
if (dbObjMap) {
|
|
508
|
-
const sliceArtefacts = await analyzeProject(
|
|
509
|
-
|
|
548
|
+
const sliceArtefacts = await evinserModule.analyzeProject(
|
|
549
|
+
dbObjMap,
|
|
550
|
+
evinseOptions
|
|
551
|
+
);
|
|
552
|
+
const evinseJson = evinserModule.createEvinseFile(
|
|
553
|
+
sliceArtefacts,
|
|
554
|
+
evinseOptions
|
|
555
|
+
);
|
|
510
556
|
bomNSData.bomJson = evinseJson;
|
|
511
|
-
if (
|
|
557
|
+
if (options.print && evinseJson) {
|
|
512
558
|
printOccurrences(evinseJson);
|
|
513
559
|
printCallStack(evinseJson);
|
|
514
560
|
printReachables(sliceArtefacts);
|
|
@@ -517,22 +563,22 @@ const checkPermissions = (filePath) => {
|
|
|
517
563
|
}
|
|
518
564
|
}
|
|
519
565
|
// Perform automatic validation
|
|
520
|
-
if (
|
|
566
|
+
if (options.validate) {
|
|
521
567
|
if (!validateBom(bomNSData.bomJson)) {
|
|
522
568
|
process.exit(1);
|
|
523
569
|
}
|
|
524
570
|
}
|
|
525
571
|
// Automatically submit the bom data
|
|
526
|
-
if (
|
|
572
|
+
if (options.serverUrl && options.serverUrl != true && options.apiKey) {
|
|
527
573
|
try {
|
|
528
|
-
const dbody = await submitBom(
|
|
574
|
+
const dbody = await submitBom(options, bomNSData.bomJson);
|
|
529
575
|
console.log("Response from server", dbody);
|
|
530
576
|
} catch (err) {
|
|
531
577
|
console.log(err);
|
|
532
578
|
}
|
|
533
579
|
}
|
|
534
580
|
|
|
535
|
-
if (
|
|
581
|
+
if (options.print && bomNSData.bomJson && bomNSData.bomJson.components) {
|
|
536
582
|
printDependencyTree(bomNSData.bomJson);
|
|
537
583
|
printTable(bomNSData.bomJson);
|
|
538
584
|
}
|