@cyclonedx/cdxgen 9.9.1 → 9.9.3

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 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.8" |
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
@@ -151,6 +150,7 @@ const args = yargs(hideBin(process.argv))
151
150
  })
152
151
  .option("install-deps", {
153
152
  type: "boolean",
153
+ hidden: true,
154
154
  default: true,
155
155
  description:
156
156
  "Install dependencies automatically for some projects. Defaults to true but disabled for containers and oci scans. Use --no-install-deps to disable this feature."
@@ -204,10 +204,27 @@ const args = yargs(hideBin(process.argv))
204
204
  "The person(s) who created the BOM. Set this value if you're intending the modify the BOM and claim authorship.",
205
205
  default: "OWASP Foundation"
206
206
  })
207
+ .option("profile", {
208
+ description: "BOM profile to use for generation. Default generic.",
209
+ default: "generic",
210
+ choices: [
211
+ "appsec",
212
+ "research",
213
+ "operational",
214
+ "threat-modeling",
215
+ "license-compliance",
216
+ "generic"
217
+ ]
218
+ })
219
+ .option("exclude", {
220
+ description: "Additional glob pattern(s) to ignore",
221
+ hidden: true
222
+ })
207
223
  .completion("completion", "Generate bash/zsh completion")
208
224
  .array("filter")
209
225
  .array("only")
210
226
  .array("author")
227
+ .array("exclude")
211
228
  .option("auto-compositions", {
212
229
  type: "boolean",
213
230
  default: true,
@@ -259,6 +276,32 @@ if (process.argv[1].includes("obom") && !args.type) {
259
276
  args.type = "os";
260
277
  }
261
278
 
279
+ const applyProfile = (options) => {
280
+ switch (options.profile) {
281
+ case "appsec":
282
+ options.deep = true;
283
+ break;
284
+ case "research":
285
+ options.deep = true;
286
+ options.evidence = true;
287
+ process.env.CDX_MAVEN_INCLUDE_TEST_SCOPE = true;
288
+ process.env.ASTGEN_IGNORE_DIRS = "";
289
+ process.env.ASTGEN_IGNORE_FILE_PATTERN = "";
290
+ break;
291
+ case "operational":
292
+ options.projectType = options.projectType || "os";
293
+ break;
294
+ case "threat-modeling": // unused
295
+ break;
296
+ case "license-compliance":
297
+ process.env.FETCH_LICENSE = true;
298
+ break;
299
+ default:
300
+ break;
301
+ }
302
+ return options;
303
+ };
304
+
262
305
  /**
263
306
  * Command line options
264
307
  */
@@ -266,8 +309,10 @@ const options = Object.assign({}, args, {
266
309
  projectType: args.type,
267
310
  multiProject: args.recurse,
268
311
  noBabel: args.noBabel || args.babel === false,
269
- project: args.projectId
312
+ project: args.projectId,
313
+ deep: args.deep || args.evidence
270
314
  });
315
+ applyProfile(options);
271
316
 
272
317
  /**
273
318
  * Check for node >= 20 permissions
@@ -306,7 +351,7 @@ const checkPermissions = (filePath) => {
306
351
  */
307
352
  (async () => {
308
353
  // Start SBOM server
309
- if (args.server) {
354
+ if (options.server) {
310
355
  const serverModule = await import("../server.js");
311
356
  return serverModule.start(options);
312
357
  }
@@ -323,15 +368,15 @@ const checkPermissions = (filePath) => {
323
368
  bomNSData = postProcess(bomNSData, options);
324
369
  }
325
370
  if (
326
- args.output &&
327
- (typeof args.output === "string" || args.output instanceof String)
371
+ options.output &&
372
+ (typeof options.output === "string" || options.output instanceof String)
328
373
  ) {
329
374
  if (bomNSData.bomXmlFiles) {
330
375
  console.log("BOM files produced:", bomNSData.bomXmlFiles);
331
376
  } else {
332
- const jsonFile = args.output.replace(".xml", ".json");
377
+ const jsonFile = options.output.replace(".xml", ".json");
333
378
  // Create bom json file
334
- if (!args.output.endsWith(".xml") && bomNSData.bomJson) {
379
+ if (!options.output.endsWith(".xml") && bomNSData.bomJson) {
335
380
  let jsonPayload = undefined;
336
381
  if (
337
382
  typeof bomNSData.bomJson === "string" ||
@@ -345,7 +390,7 @@ const checkPermissions = (filePath) => {
345
390
  }
346
391
  if (
347
392
  jsonPayload &&
348
- (args.generateKeyAndSign ||
393
+ (options.generateKeyAndSign ||
349
394
  (process.env.SBOM_SIGN_ALGORITHM &&
350
395
  process.env.SBOM_SIGN_ALGORITHM !== "none" &&
351
396
  process.env.SBOM_SIGN_PRIVATE_KEY &&
@@ -358,7 +403,7 @@ const checkPermissions = (filePath) => {
358
403
  let privateKeyToUse = undefined;
359
404
  let jwkPublicKey = undefined;
360
405
  let publicKeyFile = undefined;
361
- if (args.generateKeyAndSign) {
406
+ if (options.generateKeyAndSign) {
362
407
  const jdirName = dirname(jsonFile);
363
408
  publicKeyFile = join(jdirName, "public.key");
364
409
  const privateKeyFile = join(jdirName, "private.key");
@@ -468,8 +513,8 @@ const checkPermissions = (filePath) => {
468
513
  }
469
514
  }
470
515
  // Create bom xml file
471
- if (args.output.endsWith(".xml") && bomNSData.bomXml) {
472
- fs.writeFileSync(args.output, bomNSData.bomXml);
516
+ if (options.output.endsWith(".xml") && bomNSData.bomXml) {
517
+ fs.writeFileSync(options.output, bomNSData.bomXml);
473
518
  }
474
519
  //
475
520
  if (bomNSData.nsMapping && Object.keys(bomNSData.nsMapping).length) {
@@ -478,7 +523,7 @@ const checkPermissions = (filePath) => {
478
523
  console.log("Namespace mapping file written to", nsFile);
479
524
  }
480
525
  }
481
- } else if (!args.print) {
526
+ } else if (!options.print) {
482
527
  if (bomNSData.bomJson) {
483
528
  console.log(JSON.stringify(bomNSData.bomJson, null, 2));
484
529
  } else if (bomNSData.bomXml) {
@@ -489,7 +534,8 @@ const checkPermissions = (filePath) => {
489
534
  }
490
535
  }
491
536
  // Evidence generation
492
- if (args.evidence) {
537
+ if (options.evidence) {
538
+ const evinserModule = await import("../evinser.js");
493
539
  const evinseOptions = {
494
540
  _: args._,
495
541
  input: options.output,
@@ -503,12 +549,18 @@ const checkPermissions = (filePath) => {
503
549
  dataFlowSlicesFile: options.dataFlowSlicesFile,
504
550
  reachablesSlicesFile: options.reachablesSlicesFile
505
551
  };
506
- const dbObjMap = await prepareDB(evinseOptions);
552
+ const dbObjMap = await evinserModule.prepareDB(evinseOptions);
507
553
  if (dbObjMap) {
508
- const sliceArtefacts = await analyzeProject(dbObjMap, evinseOptions);
509
- const evinseJson = createEvinseFile(sliceArtefacts, evinseOptions);
554
+ const sliceArtefacts = await evinserModule.analyzeProject(
555
+ dbObjMap,
556
+ evinseOptions
557
+ );
558
+ const evinseJson = evinserModule.createEvinseFile(
559
+ sliceArtefacts,
560
+ evinseOptions
561
+ );
510
562
  bomNSData.bomJson = evinseJson;
511
- if (args.print && evinseJson) {
563
+ if (options.print && evinseJson) {
512
564
  printOccurrences(evinseJson);
513
565
  printCallStack(evinseJson);
514
566
  printReachables(sliceArtefacts);
@@ -517,22 +569,22 @@ const checkPermissions = (filePath) => {
517
569
  }
518
570
  }
519
571
  // Perform automatic validation
520
- if (args.validate) {
572
+ if (options.validate) {
521
573
  if (!validateBom(bomNSData.bomJson)) {
522
574
  process.exit(1);
523
575
  }
524
576
  }
525
577
  // Automatically submit the bom data
526
- if (args.serverUrl && args.serverUrl != true && args.apiKey) {
578
+ if (options.serverUrl && options.serverUrl != true && options.apiKey) {
527
579
  try {
528
- const dbody = await submitBom(args, bomNSData.bomJson);
580
+ const dbody = await submitBom(options, bomNSData.bomJson);
529
581
  console.log("Response from server", dbody);
530
582
  } catch (err) {
531
583
  console.log(err);
532
584
  }
533
585
  }
534
586
 
535
- if (args.print && bomNSData.bomJson && bomNSData.bomJson.components) {
587
+ if (options.print && bomNSData.bomJson && bomNSData.bomJson.components) {
536
588
  printDependencyTree(bomNSData.bomJson);
537
589
  printTable(bomNSData.bomJson);
538
590
  }