@cyclonedx/cdxgen 9.9.2 → 9.9.4

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
@@ -49,6 +49,8 @@ Most SBOM tools are like barcode scanners. They can scan a few package manifest
49
49
  | Gradle Cache | $HOME/caches/modules-2/files-2.1/\*\*/\*.jar | N/A | |
50
50
  | Helm Index | $HOME/.cache/helm/repository/\*\*/\*.yaml | N/A | |
51
51
  | Docker compose | docker-compose\*.yml. Images would also be scanned. | N/A | |
52
+ | Dockerfile | `*Dockerfile*` Images would also be scanned. | N/A | |
53
+ | Containerfile | `*Containerfile*`. Images would also be scanned. | N/A | |
52
54
  | Google CloudBuild configuration | cloudbuild.yaml | N/A | |
53
55
  | OpenAPI | openapi\*.json, openapi\*.yaml | N/A | |
54
56
 
@@ -173,9 +175,9 @@ Options:
173
175
  es. [boolean] [default: false]
174
176
  --spec-version CycloneDX Specification version to use. Defaults
175
177
  to 1.5 [default: 1.5]
176
- --filter Filter components containining this word in purl.
178
+ --filter Filter components containing this word in purl.
177
179
  Multiple values allowed. [array]
178
- --only Include components only containining this word in
180
+ --only Include components only containing this word in
179
181
  purl. Useful to generate BOM with first party co
180
182
  mponents alone. Multiple values allowed. [array]
181
183
  --author The person(s) who created the BOM. Set this value
package/bin/cdxgen.js CHANGED
@@ -150,6 +150,7 @@ const args = yargs(hideBin(process.argv))
150
150
  })
151
151
  .option("install-deps", {
152
152
  type: "boolean",
153
+ hidden: true,
153
154
  default: true,
154
155
  description:
155
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."
@@ -192,11 +193,11 @@ const args = yargs(hideBin(process.argv))
192
193
  })
193
194
  .option("filter", {
194
195
  description:
195
- "Filter components containining this word in purl. Multiple values allowed."
196
+ "Filter components containing this word in purl. Multiple values allowed."
196
197
  })
197
198
  .option("only", {
198
199
  description:
199
- "Include components only containining this word in purl. Useful to generate BOM with first party components alone. Multiple values allowed."
200
+ "Include components only containing this word in purl. Useful to generate BOM with first party components alone. Multiple values allowed."
200
201
  })
201
202
  .option("author", {
202
203
  description:
@@ -215,10 +216,15 @@ const args = yargs(hideBin(process.argv))
215
216
  "generic"
216
217
  ]
217
218
  })
219
+ .option("exclude", {
220
+ description: "Additional glob pattern(s) to ignore",
221
+ hidden: true
222
+ })
218
223
  .completion("completion", "Generate bash/zsh completion")
219
224
  .array("filter")
220
225
  .array("only")
221
226
  .array("author")
227
+ .array("exclude")
222
228
  .option("auto-compositions", {
223
229
  type: "boolean",
224
230
  default: true,
@@ -514,7 +520,6 @@ const checkPermissions = (filePath) => {
514
520
  if (bomNSData.nsMapping && Object.keys(bomNSData.nsMapping).length) {
515
521
  const nsFile = jsonFile + ".map";
516
522
  fs.writeFileSync(nsFile, JSON.stringify(bomNSData.nsMapping));
517
- console.log("Namespace mapping file written to", nsFile);
518
523
  }
519
524
  }
520
525
  } else if (!options.print) {
package/docker.js CHANGED
@@ -126,8 +126,8 @@ const getDefaultOptions = () => {
126
126
  opts.prefixUrl = isWin
127
127
  ? WIN_LOCAL_TLS
128
128
  : isDockerRootless
129
- ? `http://unix:${homedir()}/.docker/run/docker.sock:`
130
- : "http://unix:/var/run/docker.sock:";
129
+ ? `http://unix:${homedir()}/.docker/run/docker.sock:`
130
+ : "http://unix:/var/run/docker.sock:";
131
131
  }
132
132
  }
133
133
  } else {
package/evinser.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  collectMvnDependencies
8
8
  } from "./utils.js";
9
9
  import { tmpdir } from "node:os";
10
- import path, { basename } from "node:path";
10
+ import path from "node:path";
11
11
  import fs from "node:fs";
12
12
  import * as db from "./db.js";
13
13
  import { PackageURL } from "packageurl-js";
@@ -94,15 +94,30 @@ export const catalogMavenDeps = async (
94
94
  Namespaces,
95
95
  options = {}
96
96
  ) => {
97
- console.log("About to collect jar dependencies for the path", dirPath);
98
- const mavenCmd = getMavenCommand(dirPath, dirPath);
99
- // collect all jars including from the cache if data-flow mode is enabled
100
- const jarNSMapping = collectMvnDependencies(
101
- mavenCmd,
102
- dirPath,
103
- false,
104
- options.withDeepJarCollector
105
- );
97
+ let jarNSMapping = undefined;
98
+ if (fs.existsSync(path.join(dirPath, "bom.json.map"))) {
99
+ try {
100
+ const mapData = JSON.parse(
101
+ fs.readFileSync(path.join(dirPath, "bom.json.map"))
102
+ );
103
+ if (mapData && Object.keys(mapData).length) {
104
+ jarNSMapping = mapData;
105
+ }
106
+ } catch (err) {
107
+ // ignore
108
+ }
109
+ }
110
+ if (!jarNSMapping) {
111
+ console.log("About to collect jar dependencies for the path", dirPath);
112
+ const mavenCmd = getMavenCommand(dirPath, dirPath);
113
+ // collect all jars including from the cache if data-flow mode is enabled
114
+ jarNSMapping = collectMvnDependencies(
115
+ mavenCmd,
116
+ dirPath,
117
+ false,
118
+ options.withDeepJarCollector
119
+ );
120
+ }
106
121
  if (jarNSMapping) {
107
122
  for (const purl of Object.keys(jarNSMapping)) {
108
123
  purlsJars[purl] = jarNSMapping[purl].jarFile;
@@ -317,9 +332,6 @@ export const analyzeProject = async (dbObjMap, options) => {
317
332
  if (retMap && retMap.slicesFile && fs.existsSync(retMap.slicesFile)) {
318
333
  usageSlice = JSON.parse(fs.readFileSync(retMap.slicesFile, "utf-8"));
319
334
  usagesSlicesFile = retMap.slicesFile;
320
- console.log(
321
- `To speed up this step, cache ${usagesSlicesFile} and invoke evinse with the --usages-slices-file argument.`
322
- );
323
335
  }
324
336
  }
325
337
  if (usageSlice && Object.keys(usageSlice).length) {
@@ -349,9 +361,6 @@ export const analyzeProject = async (dbObjMap, options) => {
349
361
  if (retMap && retMap.slicesFile && fs.existsSync(retMap.slicesFile)) {
350
362
  dataFlowSlicesFile = retMap.slicesFile;
351
363
  dataFlowSlice = JSON.parse(fs.readFileSync(retMap.slicesFile, "utf-8"));
352
- console.log(
353
- `To speed up this step, cache ${dataFlowSlicesFile} and invoke evinse with the --data-flow-slices-file argument.`
354
- );
355
364
  }
356
365
  }
357
366
  }
@@ -381,9 +390,6 @@ export const analyzeProject = async (dbObjMap, options) => {
381
390
  reachablesSlice = JSON.parse(
382
391
  fs.readFileSync(retMap.slicesFile, "utf-8")
383
392
  );
384
- console.log(
385
- `To speed up this step, cache ${reachablesSlicesFile} and invoke evinse with the --reachables-slices-file argument.`
386
- );
387
393
  }
388
394
  }
389
395
  }
@@ -492,14 +498,16 @@ export const parseSliceUsages = async (
492
498
  !isFilterableType(language, userDefinedTypesMap, atype[1])
493
499
  ) {
494
500
  if (!atype[1].includes("(") && !atype[1].includes(".py")) {
495
- typesToLookup.add(atype[1]);
501
+ typesToLookup.add(simplifyType(atype[1]));
496
502
  // Javascript calls can be resolved to a precise line number only from the call nodes
497
503
  if (
498
504
  ["javascript", "js", "ts", "typescript"].includes(language) &&
499
505
  ausageLine
500
506
  ) {
501
507
  if (atype[1].includes(":")) {
502
- typesToLookup.add(atype[1].split("::")[0].replace(/:/g, "/"));
508
+ typesToLookup.add(
509
+ simplifyType(atype[1].split("::")[0].replace(/:/g, "/"))
510
+ );
503
511
  }
504
512
  addToOverrides(lKeyOverrides, atype[1], fileName, ausageLine);
505
513
  }
@@ -526,7 +534,7 @@ export const parseSliceUsages = async (
526
534
  !acall?.resolvedMethod.includes("(") &&
527
535
  !acall?.resolvedMethod.includes(".py")
528
536
  ) {
529
- typesToLookup.add(acall?.resolvedMethod);
537
+ typesToLookup.add(simplifyType(acall?.resolvedMethod));
530
538
  // Javascript calls can be resolved to a precise line number only from the call nodes
531
539
  if (acall.lineNumber) {
532
540
  addToOverrides(
@@ -554,10 +562,12 @@ export const parseSliceUsages = async (
554
562
  for (const aparamType of acall?.paramTypes || []) {
555
563
  if (!isFilterableType(language, userDefinedTypesMap, aparamType)) {
556
564
  if (!aparamType.includes("(") && !aparamType.includes(".py")) {
557
- typesToLookup.add(aparamType);
565
+ typesToLookup.add(simplifyType(aparamType));
558
566
  if (acall.lineNumber) {
559
567
  if (aparamType.includes(":")) {
560
- typesToLookup.add(aparamType.split("::")[0].replace(/:/g, "/"));
568
+ typesToLookup.add(
569
+ simplifyType(aparamType.split("::")[0].replace(/:/g, "/"))
570
+ );
561
571
  }
562
572
  addToOverrides(
563
573
  lKeyOverrides,
@@ -603,7 +613,7 @@ export const parseSliceUsages = async (
603
613
  } else {
604
614
  // Check the namespaces db
605
615
  let nsHits = typePurlsCache[atype];
606
- if (["java", "jar"].includes(language)) {
616
+ if (!nsHits && ["java", "jar"].includes(language)) {
607
617
  nsHits = await dbObjMap.Namespaces.findAll({
608
618
  attributes: ["purl"],
609
619
  where: {
@@ -623,6 +633,9 @@ export const parseSliceUsages = async (
623
633
  }
624
634
  }
625
635
  typePurlsCache[atype] = nsHits;
636
+ } else {
637
+ // Avoid persistent lookups
638
+ typePurlsCache[atype] = [];
626
639
  }
627
640
  }
628
641
  }
@@ -783,7 +796,7 @@ export const detectServicesFromUDT = (
783
796
  const endpoints = extractEndpoints(language, fields[0].name);
784
797
  let serviceName = "service";
785
798
  if (audt.fileName) {
786
- serviceName = `${basename(
799
+ serviceName = `${path.basename(
787
800
  audt.fileName.replace(".py", "")
788
801
  )}-service`;
789
802
  }
@@ -828,7 +841,7 @@ export const extractEndpoints = (language, code) => {
828
841
  case "jar":
829
842
  if (
830
843
  code.startsWith("@") &&
831
- code.includes("Mapping") &&
844
+ (code.includes("Mapping") || code.includes("Path")) &&
832
845
  code.includes("(")
833
846
  ) {
834
847
  const matches = code.match(/['"](.*?)['"]/gi) || [];
@@ -1184,6 +1197,16 @@ export const framePicker = (dfFrames) => {
1184
1197
  return aframe;
1185
1198
  };
1186
1199
 
1200
+ /**
1201
+ * Method to simplify types. For example, arrays ending with [] could be simplified.
1202
+ *
1203
+ * @param {string} typeFullName Full name of the type to simplify
1204
+ * @returns Simplified type string
1205
+ */
1206
+ export const simplifyType = (typeFullName) => {
1207
+ return typeFullName.replace("[]", "");
1208
+ };
1209
+
1187
1210
  export const getClassTypeFromSignature = (language, typeFullName) => {
1188
1211
  if (["java", "jar"].includes(language) && typeFullName.includes(":")) {
1189
1212
  typeFullName = typeFullName.split(":")[0];
@@ -1219,7 +1242,7 @@ export const getClassTypeFromSignature = (language, typeFullName) => {
1219
1242
  if (typeFullName.includes("$")) {
1220
1243
  typeFullName = typeFullName.split("$")[0];
1221
1244
  }
1222
- return typeFullName;
1245
+ return simplifyType(typeFullName);
1223
1246
  };
1224
1247
 
1225
1248
  const addToOverrides = (lKeyOverrides, atype, fileName, ausageLineNumber) => {