@cyclonedx/cdxgen 9.8.0 → 9.8.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 CHANGED
@@ -2,17 +2,16 @@
2
2
 
3
3
  ![cdxgen logo](cdxgen.png)
4
4
 
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.
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 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.
7
+ When used with plugins, cdxgen could generate an OBoM for Linux docker images and even VMs running Linux or Windows operating systems. cdxgen also includes an evinse tool to generate component evidence and SaaSBoM for some languages.
8
8
 
9
9
  NOTE:
10
10
 
11
11
  CycloneDX 1.5 specification is new and unsupported by many downstream tools. Use version 8.6.0 for 1.4 compatibility or pass the argument `--spec-version 1.4`.
12
12
 
13
13
  ## Why cdxgen?
14
-
15
- A typical application might comprise of several repos, components, and libraries linked together. Traditional techniques to generate a single SBoM per language or package manifest do not work in enterprise environments. So we built cdxgen - the universal polyglot SBoM generator!
14
+ A typical application might have several repos, components, and libraries. Traditional techniques to generate a single SBoM per language or package manifest do not work in enterprise environments. So we built cdxgen - the universal polyglot SBoM generator!
16
15
 
17
16
  <img src="./docs/why-cdxgen.jpg" alt="why cdxgen" width="256">
18
17
 
@@ -56,28 +55,27 @@ NOTE:
56
55
 
57
56
  - Apache maven 3.x is required for parsing pom.xml
58
57
  - gradle or gradlew is required to parse gradle projects
59
- - sbt is required for parsing scala sbt projects. Only scala 2.10 + sbt 0.13.6+ and 2.12 + sbt 1.0+ is supported for now.
58
+ - sbt is required for parsing scala sbt projects. Only scala 2.10 + sbt 0.13.6+ and 2.12 + sbt 1.0+ are currently supported.
60
59
  - Alternatively, create a lock file using sbt-dependency-lock [plugin](https://github.com/stringbean/sbt-dependency-lock)
61
60
 
62
61
  Footnotes:
63
62
 
64
- - [1] - For multi-module application, the BoM file could include components that may not be included in the packaged war or ear file.
63
+ - [1] - For multi-module applications, the BoM file could include components not included in the packaged war or ear file.
65
64
  - [2] - Pip freeze is automatically performed to improve precision. Requires virtual environment.
66
- - [3] - Perform dotnet or nuget restore to generate project.assets.json. Without this file cdxgen would not include indirect dependencies.
67
- - [4] - See section on plugins
68
- - [5] - Powered by osquery. See section on plugins
65
+ - [3] - Perform dotnet or nuget restore to generate project.assets.json. Without this file, cdxgen would not include indirect dependencies.
66
+ - [4] - See the section on plugins
67
+ - [5] - Powered by osquery. See the section on plugins
69
68
 
70
69
  <img src="./docs/cdxgen-tree.jpg" alt="cdxgen tree" width="256">
71
70
 
72
71
  ### Automatic usage detection
72
+ For node.js projects, lock files are parsed initially, so the SBoM would include all dependencies, including dev ones. An AST parser powered by babel-parser is then used to detect packages that are imported and used by non-test code. Such imported packages would automatically set their scope property to `required` in the resulting SBoM. You can turn off this analysis by passing the argument `--no-babel`. Scope property would then be set based on the `dev` attribute in the lock file.
73
73
 
74
- For node.js projects, lock files are parsed initially so the SBoM would include all dependencies including dev dependencies. An AST parser powered by babel-parser is then used to detect packages that are imported and used by non-test code. Such imported packages would automatically have their `scope` property set to `required` in the resulting SBoM. By passing the argument `--no-babel`, you can disable this analysis. Scope property would then be set based on the `dev` attribute in the lock file.
75
-
76
- This attribute can be later used for various purposes. For example, [dep-scan](https://github.com/cyclonedx/dep-scan) use this attribute to prioritize vulnerabilities. Tools such dependency track, unfortunately, do not include this feature and hence might over-report the CVEs.
74
+ This attribute can be later used for various purposes. For example, [dep-scan](https://github.com/cyclonedx/dep-scan) uses this attribute to prioritize vulnerabilities. Unfortunately, tools such as dependency track, do not include this feature and might over-report the CVEs.
77
75
 
78
- By passing the argument `--required-only`, you can limit the SBoM to only include packages with the scope "required", commonly referred to as production or non-dev dependencies. Combine with `--no-babel` to limit this list to only non-dev dependencies based on the `dev` attribute being false in the lock files.
76
+ By passing the argument `--required-only`, you can limit the SBoM only to include packages with the scope "required", commonly called production or non-dev dependencies. Combine with `--no-babel` to limit this list to only non-dev dependencies based on the `dev` attribute being false in the lock files.
79
77
 
80
- For go, `go mod why` command is used to identify required packages. For php, composer lock file is used to distinguish required (packages) from optional (packages-dev).
78
+ For go, `go mod why` command is used to identify required packages. For php, composer lock file is parsed to distinguish required (packages) from optional (packages-dev).
81
79
 
82
80
  ## Usage
83
81
 
@@ -99,7 +97,7 @@ $ brew install cdxgen
99
97
  Deno install is also supported.
100
98
 
101
99
  ```shell
102
- deno install --allow-read --allow-env --allow-run --allow-sys=uid,systemMemoryInfo --allow-write --allow-net -n cdxgen "npm:@cyclonedx/cdxgen/cdxgen"
100
+ deno install --allow-read --allow-env --allow-run --allow-sys=uid,systemMemoryInfo,gid --allow-write --allow-net -n cdxgen "npm:@cyclonedx/cdxgen/cdxgen"
103
101
  ```
104
102
 
105
103
  You can also use the cdxgen container image
@@ -175,7 +173,7 @@ $ cdxgen -h
175
173
  -v, --version Show version number [boolean]
176
174
  ```
177
175
 
178
- All boolean arguments accepts `--no` prefix to toggle the behavior.
176
+ All boolean arguments accept `--no` prefix to toggle the behavior.
179
177
 
180
178
  ## Example
181
179
 
@@ -185,7 +183,7 @@ Minimal example.
185
183
  cdxgen -o bom.json
186
184
  ```
187
185
 
188
- For a java project. This would automatically detect maven, gradle or sbt and build bom accordingly
186
+ For a java project. cdxgen would automatically detect maven, gradle, or sbt and build bom accordingly
189
187
 
190
188
  ```shell
191
189
  cdxgen -t java -o bom.json
@@ -203,7 +201,7 @@ To recursively generate a single BoM for all languages pass `-r` argument.
203
201
  cdxgen -r -o bom.json
204
202
  ```
205
203
 
206
- To generate SBoM for an older specification version such as 1.4, pass the version using the `--spec-version` argument.
204
+ To generate SBoM for an older specification version, such as 1.4, pass the version number using the `--spec-version` argument.
207
205
 
208
206
  ```shell
209
207
  cdxgen -r -o bom.json --spec-version 1.4
@@ -216,15 +214,15 @@ To generate SBoM for C or Python, ensure Java >= 17 is installed.
216
214
  cdxgen -t c -o bom.json
217
215
  ```
218
216
 
219
- NOTE: cdxgen is known to freeze with Java 8 or 11 so ensure >= 17 is installed and JAVA_HOME environment variable configured correctly. If in doubt, use the cdxgen container image.
217
+ NOTE: cdxgen is known to freeze with Java 8 or 11, so ensure >= 17 is installed and JAVA_HOME environment variable is configured correctly. If in doubt, use the cdxgen container image.
220
218
 
221
219
  ## Universal SBoM
222
220
 
223
- By passing the type `-t universal`, cdxgen could be forced to opportunistically collect as many components and services as possible by scanning all package, container and kubernetes manifests. The resulting SBoM could have over thousand components thus requiring additional triaging before use with traditional SCA tools.
221
+ By passing the type argument `-t universal`, cdxgen could be forced to opportunistically collect as many components and services as possible by scanning all package, container, and Kubernetes manifests. The resulting SBoM could have over a thousand components, thus requiring additional triaging before use with traditional SCA tools.
224
222
 
225
223
  ## SBoM server
226
224
 
227
- Invoke cdxgen with `--server` argument to run it in a server mode. By default, it listens to port `9090` which can be customized with the arguments `--server-host` and `--server-port`.
225
+ Invoke cdxgen with `--server` argument to run it in server mode. By default, it listens to port `9090`, which can be customized with the arguments `--server-host` and `--server-port`.
228
226
 
229
227
  ```shell
230
228
  cdxgen --server
@@ -236,7 +234,7 @@ Or use the container image.
236
234
  docker run --rm -v /tmp:/tmp -p 9090:9090 -v $(pwd):/app:rw -t ghcr.io/cyclonedx/cdxgen -r /app --server --server-host 0.0.0.0
237
235
  ```
238
236
 
239
- Use curl or your favourite tool to pass arguments to the `/sbom` route.
237
+ Use curl or your favorite tool to pass arguments to the `/sbom` route.
240
238
 
241
239
  ### Scanning a local path
242
240
 
@@ -274,7 +272,7 @@ cdxgen app.war
274
272
 
275
273
  ## Resolving class names
276
274
 
277
- Sometimes it is necessary to resolve class names contained in jar files. By passing an optional argument `--resolve-class`, it is possible to get cdxgen create a separate mapping file with the jar name (including the version) as the key and class names list as a value.
275
+ Sometimes, it is necessary to resolve class names contained in jar files. By passing an optional argument `--resolve-class`, it is possible to get cdxgen to create a separate mapping file with the jar name (including the version) as the key and class names list as a value.
278
276
 
279
277
  ```shell
280
278
  cdxgen -t java --resolve-class -o bom.json
@@ -284,7 +282,7 @@ This would create a bom.json.map file with the jar - class name mapping. Refer t
284
282
 
285
283
  ## Resolving licenses
286
284
 
287
- cdxgen can automatically query the public registries such as maven or npm or nuget to resolve the package licenses. This is a time consuming operation and is disabled by default. To enable, set the environment variable `FETCH_LICENSE` to `true` as shown.
285
+ cdxgen can automatically query public registries such as maven, npm, or nuget to resolve the package licenses. This is a time-consuming operation and is disabled by default. To enable, set the environment variable `FETCH_LICENSE` to `true`, as shown.
288
286
 
289
287
  ```bash
290
288
  export FETCH_LICENSE=true
@@ -301,6 +299,7 @@ cdxgen can retain the dependency tree under the `dependencies` attribute for a s
301
299
  - Gradle
302
300
  - Scala SBT
303
301
  - Python (requirements.txt, setup.py, pyproject.toml, poetry.lock)
302
+ - csharp (projects.assets.json)
304
303
 
305
304
  ## Environment variables
306
305
 
@@ -370,15 +369,11 @@ podman save -q --format oci-archive -o /tmp/slim.tar shiftleft/scan-slim
370
369
  cdxgen /tmp/slim.tar -o /tmp/bom.json -t docker
371
370
  ```
372
371
 
373
- NOTE:
374
-
375
- - Only application related packages are collected by cdxgen. Support for OS installed packages is coming soon.
376
-
377
372
  ### Podman in rootless mode
378
373
 
379
374
  Setup podman in either [rootless](https://github.com/containers/podman/blob/master/docs/tutorials/rootless_tutorial.md) or [remote](https://github.com/containers/podman/blob/master/docs/tutorials/mac_win_client.md) mode
380
375
 
381
- On Linux, do not forget to start the podman socket which is required for API access.
376
+ Do not forget to start the podman socket required for API access on Linux.
382
377
 
383
378
  ```shell
384
379
  systemctl --user enable --now podman.socket
@@ -396,27 +391,27 @@ obom
396
391
  # cdxgen -t os
397
392
  ```
398
393
 
399
- 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.
394
+ 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.
400
395
 
401
396
  ## Generating SaaSBoM and component evidences
402
397
 
403
398
  See [evinse mode](./ADVANCED.md) in the advanced documentation.
404
399
 
405
- ## SBoM signing
400
+ ## BoM signing
406
401
 
407
- cdxgen can sign the generated SBoM json file to increase authenticity and non-repudiation capabilities. To enable this, set the following environment variables.
402
+ cdxgen can sign the generated BoM json file to increase authenticity and non-repudiation capabilities. To enable this, set the following environment variables.
408
403
 
409
404
  - SBOM_SIGN_ALGORITHM: Algorithm. Example: RS512
410
405
  - SBOM_SIGN_PRIVATE_KEY: Location to the RSA private key
411
406
  - SBOM_SIGN_PUBLIC_KEY: Optional. Location to the RSA public key
412
407
 
413
- To generate test public/private key pairs, you can run cdxgen by passing the argument `--generate-key-and-sign`. The generated json file would have an attribute called `signature` which could be used for validation. [jwt.io](https://jwt.io) is a known site that could be used for such signature validation.
408
+ To generate test public/private key pairs, you can run cdxgen by passing the argument `--generate-key-and-sign`. The generated json file would have an attribute called `signature`, which could be used for validation. [jwt.io](https://jwt.io) is a known site that could be used for such signature validation.
414
409
 
415
410
  ![SBoM signing](sbom-sign.jpg)
416
411
 
417
412
  ### Verifying the signature
418
413
 
419
- Use the bundled `cdx-verify` command which supports verifying a single signature added at the bom level.
414
+ Use the bundled `cdx-verify` command, which supports verifying a single signature added at the bom level.
420
415
 
421
416
  ```shell
422
417
  npm install -g @cyclonedx/cdxgen
@@ -448,7 +443,7 @@ if (validationResult) {
448
443
 
449
444
  ## Automatic services detection
450
445
 
451
- cdxgen can automatically detect names of services from YAML manifests such as docker-compose or Kubernetes or Skaffold manifests. These would be populated under the `services` attribute in the generated SBoM. With [evinse](./ADVANCED.md), additional services could be detected by parsing common annotations from the source code.
446
+ cdxgen can automatically detect names of services from YAML manifests such as docker-compose, Kubernetes, or Skaffold manifests. These would be populated under the `services` attribute in the generated SBoM. With [evinse](./ADVANCED.md), additional services could be detected by parsing common annotations from the source code.
452
447
 
453
448
  ## Conversion to SPDX format
454
449
 
@@ -471,7 +466,7 @@ Minimal example:
471
466
  import { createBom, submitBom } from "npm:@cyclonedx/cdxgen@^9.0.1";
472
467
  ```
473
468
 
474
- See the [Deno Readme](./contrib/deno/README.md) for detailed instruction.
469
+ See the [Deno Readme](./contrib/deno/README.md) for detailed instructions.
475
470
 
476
471
  ```javascript
477
472
  import { createBom, submitBom } from "@cyclonedx/cdxgen";
@@ -487,7 +482,7 @@ Refer to the [permissions document](./docs/PERMISSIONS.md)
487
482
 
488
483
  ## Contributing
489
484
 
490
- Follow the usual PR process but prior to raising a PR run the following commands.
485
+ Follow the usual PR process, but before raising a PR, run the following commands.
491
486
 
492
487
  ```bash
493
488
  npm run lint
@@ -497,4 +492,4 @@ npm test
497
492
 
498
493
  ## Enterprise support
499
494
 
500
- Enterprise support including custom development and integration services are available via [AppThreat Ltd](https://www.appthreat.com). Free community support is also available via [discord](https://discord.gg/tmmtjCEHNV).
495
+ Enterprise support, including custom development and integration services, is available via [AppThreat Ltd](https://www.appthreat.com). Free community support is also available via [Discord](https://discord.gg/tmmtjCEHNV).
package/binary.js CHANGED
@@ -3,7 +3,7 @@ import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
3
3
  import { join, dirname, basename } from "node:path";
4
4
  import { spawnSync } from "node:child_process";
5
5
  import { PackageURL } from "packageurl-js";
6
- import { DEBUG_MODE } from "./utils.js";
6
+ import { DEBUG_MODE, findLicenseId } from "./utils.js";
7
7
 
8
8
  import { fileURLToPath } from "node:url";
9
9
 
@@ -509,7 +509,34 @@ export const getOSPackages = (src) => {
509
509
  Array.isArray(comp.licenses) &&
510
510
  comp.licenses.length
511
511
  ) {
512
- comp.licenses = [comp.licenses[0]];
512
+ const newLicenses = [];
513
+ for (const alic of comp.licenses) {
514
+ if (alic.license.name) {
515
+ // Licenses array can either be made of expressions or id/name but not both
516
+ if (
517
+ comp.licenses.length == 1 &&
518
+ (alic.license.name.toUpperCase().includes(" AND ") ||
519
+ alic.license.name.toUpperCase().includes(" OR "))
520
+ ) {
521
+ newLicenses.push({ expression: alic.license.name });
522
+ } else {
523
+ const possibleId = findLicenseId(alic.license.name);
524
+ if (possibleId !== alic.license.name) {
525
+ newLicenses.push({ license: { id: possibleId } });
526
+ } else {
527
+ newLicenses.push({
528
+ license: { name: alic.license.name }
529
+ });
530
+ }
531
+ }
532
+ } else if (
533
+ Object.keys(alic).length &&
534
+ Object.keys(alic.license).length
535
+ ) {
536
+ newLicenses.push(alic);
537
+ }
538
+ }
539
+ comp.licenses = newLicenses;
513
540
  }
514
541
  // Fix hashes
515
542
  if (
@@ -58,6 +58,18 @@
58
58
  "BSD (3-clause)"
59
59
  ]
60
60
  },
61
+ {
62
+ "exp": "BSD-4-Clause",
63
+ "names": [
64
+ "BSD 4 Clause",
65
+ "BSD 4-Clause",
66
+ "BSD-4-Clause",
67
+ "BSD 4-Clause License",
68
+ "The BSD 4-Clause License",
69
+ "BSD 4-Clause \"New\" or \"Revised\" License (BSD-4-Clause)",
70
+ "BSD (4-clause)"
71
+ ]
72
+ },
61
73
  {
62
74
  "exp": "CDDL-1.0",
63
75
  "names": [
@@ -177,6 +189,8 @@
177
189
  {
178
190
  "exp": "GPL-2.0-only",
179
191
  "names": [
192
+ "GPLv2",
193
+ "GPL-2.0",
180
194
  "GNU General Public License (GPL) version 2",
181
195
  "GNU General Public License (GPL) version 2.0",
182
196
  "GNU General Public License v2",
@@ -216,12 +230,14 @@
216
230
  "GNU General Public License v3",
217
231
  "GNU General Public License v3.0",
218
232
  "GNU General Public License as published by the Free Software Foundation, version 3.",
219
- "GPL-3"
233
+ "GPL-3",
234
+ "GPL-3.0"
220
235
  ]
221
236
  },
222
237
  {
223
238
  "exp": "GPL-3.0-or-later",
224
239
  "names": [
240
+ "GPLv3+",
225
241
  "GNU General Public License (GPL) version 3, or any later version",
226
242
  "GNU General Public License (GPL) version 3.0, or any later version",
227
243
  "GNU General Public License v3 or later",
package/index.js CHANGED
@@ -655,8 +655,8 @@ function addComponent(
655
655
  }
656
656
  if (!isRootPkg) {
657
657
  const pkgIdentifier = parsePackageJsonName(pkg.name);
658
- const author = pkg.author || "";
659
- const publisher = pkg.publisher || "";
658
+ const author = pkg.author || undefined;
659
+ const publisher = pkg.publisher || undefined;
660
660
  let group = pkg.group || pkgIdentifier.scope;
661
661
  // Create empty group
662
662
  group = group || "";
@@ -684,7 +684,7 @@ function addComponent(
684
684
  purlString = decodeURIComponent(purlString);
685
685
  let description = { "#cdata": pkg.description };
686
686
  if (format === "json") {
687
- description = pkg.description || "";
687
+ description = pkg.description || undefined;
688
688
  }
689
689
  let compScope = pkg.scope;
690
690
  if (allImports) {
@@ -1267,7 +1267,7 @@ export const createJavaBom = async (path, options) => {
1267
1267
  );
1268
1268
  } else {
1269
1269
  console.log(
1270
- "1. Java version requirement: cdxgen container image bundles Java 20 with maven 3.9 which might be incompatible."
1270
+ "1. Java version requirement: cdxgen container image bundles Java 21 with maven 3.9 which might be incompatible."
1271
1271
  );
1272
1272
  }
1273
1273
  console.log(
@@ -2985,7 +2985,13 @@ export const createCppBom = (path, options) => {
2985
2985
  }
2986
2986
  }
2987
2987
  }
2988
- if (!["docker", "oci", "os"].includes(options.projectType)) {
2988
+ // The need for java >= 17 with atom is causing confusions since there could be C projects
2989
+ // inside of other project types. So we currently limit this analyis only when -t argument
2990
+ // is used.
2991
+ if (
2992
+ !["docker", "oci", "os"].includes(options.projectType) &&
2993
+ (!options.createMultiXBom || options.deep)
2994
+ ) {
2989
2995
  let osPkgsList = [];
2990
2996
  // Case 1: Development libraries installed in this OS environment might be used for build
2991
2997
  // We collect OS packages with the word dev in the name using osquery here
@@ -3012,10 +3018,12 @@ export const createCppBom = (path, options) => {
3012
3018
  pkgList = pkgList.concat(dlist);
3013
3019
  }
3014
3020
  }
3015
- if (!parentComponent) {
3016
- parentComponent = createDefaultParentComponent(path, "conan", options);
3021
+ if (!options.createMultiXBom) {
3022
+ if (!parentComponent) {
3023
+ parentComponent = createDefaultParentComponent(path, "conan", options);
3024
+ }
3025
+ options.parentComponent = parentComponent;
3017
3026
  }
3018
- options.parentComponent = parentComponent;
3019
3027
  return buildBomNSData(options, pkgList, "conan", {
3020
3028
  src: path,
3021
3029
  parentComponent
@@ -4170,6 +4178,7 @@ export const createMultiXBom = async (pathList, options) => {
4170
4178
  let bomData = undefined;
4171
4179
  let parentComponent = determineParentComponent(options) || {};
4172
4180
  let parentSubComponents = [];
4181
+ options.createMultiXBom = true;
4173
4182
  if (
4174
4183
  ["docker", "oci", "container"].includes(options.projectType) &&
4175
4184
  options.allLayersExplodedDir
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyclonedx/cdxgen",
3
- "version": "9.8.0",
3
+ "version": "9.8.1",
4
4
  "description": "Creates CycloneDX Software Bill-of-Materials (SBOM) from source or container image",
5
5
  "homepage": "http://github.com/cyclonedx/cdxgen",
6
6
  "author": "Prabhu Subramanian <prabhu@appthreat.com>",
package/utils.js CHANGED
@@ -1745,7 +1745,10 @@ export const parseGradleProjects = function (rawOutput) {
1745
1745
  // Include all projects including test projects
1746
1746
  if (projName.startsWith(":")) {
1747
1747
  // Handle the case where the project name could have a space. Eg: +--- project :app (*)
1748
- projects.add(projName.split(" ")[0]);
1748
+ const tmpName = projName.split(" ")[0];
1749
+ if (tmpName.length > 1) {
1750
+ projects.add(tmpName);
1751
+ }
1749
1752
  }
1750
1753
  }
1751
1754
  } else if (l.includes("--- project ")) {
@@ -1753,7 +1756,10 @@ export const parseGradleProjects = function (rawOutput) {
1753
1756
  if (tmpB && tmpB.length > 1) {
1754
1757
  const projName = tmpB[1];
1755
1758
  if (projName.startsWith(":")) {
1756
- projects.add(projName.split(" ")[0]);
1759
+ const tmpName = projName.split(" ")[0];
1760
+ if (tmpName.length > 1) {
1761
+ projects.add(tmpName);
1762
+ }
1757
1763
  }
1758
1764
  }
1759
1765
  }
@@ -1864,7 +1870,7 @@ export const executeGradleProperties = function (dir, rootPath, subProject) {
1864
1870
  } else {
1865
1871
  console.error(result.stdout, result.stderr);
1866
1872
  console.log(
1867
- "1. Check if the correct version of java and gradle are installed and available in PATH. For example, some project might require Java 11 with gradle 7.\n cdxgen container image bundles Java 20 with gradle 8 which might be incompatible."
1873
+ "1. Check if the correct version of java and gradle are installed and available in PATH. For example, some project might require Java 11 with gradle 7.\n cdxgen container image bundles Java 21 with gradle 8 which might be incompatible."
1868
1874
  );
1869
1875
  }
1870
1876
  if (result.stderr.includes("not get unknown property")) {
@@ -2057,7 +2063,7 @@ export const parseKVDep = function (rawOutput) {
2057
2063
  */
2058
2064
  export const findLicenseId = function (name) {
2059
2065
  for (const l of licenseMapping) {
2060
- if (l.names.includes(name)) {
2066
+ if (l.names.includes(name) || l.exp.toUpperCase() === name.toUpperCase()) {
2061
2067
  return l.exp;
2062
2068
  }
2063
2069
  }
@@ -3948,7 +3954,6 @@ export const parseOpenapiSpecData = function (oaData) {
3948
3954
  oaData = JSON.parse(oaData);
3949
3955
  }
3950
3956
  } catch (e) {
3951
- console.error(e);
3952
3957
  return servlist;
3953
3958
  }
3954
3959
  const name = oaData.info.title.replace(/ /g, "-");
@@ -6010,7 +6015,9 @@ export const getGradleCommand = (srcPath, rootPath) => {
6010
6015
  */
6011
6016
  export const getMavenCommand = (srcPath, rootPath) => {
6012
6017
  let mavenCmd = "mvn";
6013
-
6018
+ // Check if the wrapper script is both available and functional
6019
+ let isWrapperReady = false;
6020
+ let isWrapperFound = false;
6014
6021
  let findMavenFile = "mvnw";
6015
6022
  if (platform() == "win32") {
6016
6023
  findMavenFile = "mvnw.bat";
@@ -6031,6 +6038,7 @@ export const getMavenCommand = (srcPath, rootPath) => {
6031
6038
  // continue regardless of error
6032
6039
  }
6033
6040
  mavenCmd = resolve(join(srcPath, findMavenFile));
6041
+ isWrapperFound = true;
6034
6042
  } else if (rootPath && existsSync(join(rootPath, findMavenFile))) {
6035
6043
  // Check if the root directory has a wrapper script
6036
6044
  try {
@@ -6039,10 +6047,35 @@ export const getMavenCommand = (srcPath, rootPath) => {
6039
6047
  // continue regardless of error
6040
6048
  }
6041
6049
  mavenCmd = resolve(join(rootPath, findMavenFile));
6042
- } else if (process.env.MVN_CMD || process.env.MAVEN_CMD) {
6043
- mavenCmd = process.env.MVN_CMD || process.env.MAVEN_CMD;
6044
- } else if (process.env.MAVEN_HOME) {
6045
- mavenCmd = join(process.env.MAVEN_HOME, "bin", "mvn");
6050
+ isWrapperFound = true;
6051
+ }
6052
+ if (isWrapperFound) {
6053
+ if (DEBUG_MODE) {
6054
+ console.log(
6055
+ "Testing the wrapper script by invoking wrapper:wrapper task"
6056
+ );
6057
+ }
6058
+ const result = spawnSync(mavenCmd, ["wrapper:wrapper"], {
6059
+ encoding: "utf-8",
6060
+ cwd: rootPath,
6061
+ timeout: TIMEOUT_MS
6062
+ });
6063
+ if (!result.error) {
6064
+ isWrapperReady = true;
6065
+ } else {
6066
+ if (DEBUG_MODE) {
6067
+ console.log(
6068
+ "Maven wrapper script test has failed. Will use the installed version of maven."
6069
+ );
6070
+ }
6071
+ }
6072
+ }
6073
+ if (!isWrapperFound || !isWrapperReady) {
6074
+ if (process.env.MVN_CMD || process.env.MAVEN_CMD) {
6075
+ mavenCmd = process.env.MVN_CMD || process.env.MAVEN_CMD;
6076
+ } else if (process.env.MAVEN_HOME) {
6077
+ mavenCmd = join(process.env.MAVEN_HOME, "bin", "mvn");
6078
+ }
6046
6079
  }
6047
6080
  return mavenCmd;
6048
6081
  };
package/utils.test.js CHANGED
@@ -346,6 +346,12 @@ test("parse gradle dependencies", () => {
346
346
  );
347
347
  expect(parsedList.pkgList.length).toEqual(6);
348
348
  expect(parsedList.dependenciesList.length).toEqual(7);
349
+ parsedList = parseGradleDep(
350
+ readFileSync("./test/data/gradle-dependencies-559.txt", {
351
+ encoding: "utf-8"
352
+ })
353
+ );
354
+ expect(parsedList.pkgList.length).toEqual(372);
349
355
  });
350
356
 
351
357
  test("parse gradle projects", () => {
@@ -493,6 +499,13 @@ test("parse gradle properties", () => {
493
499
  );
494
500
  expect(retMap.rootProject).toEqual("root");
495
501
  expect(retMap.projects).toEqual([]);
502
+ retMap = parseGradleProperties(
503
+ readFileSync("./test/data/gradle-properties-559.txt", {
504
+ encoding: "utf-8"
505
+ })
506
+ );
507
+ expect(retMap.rootProject).toEqual("failing-project");
508
+ expect(retMap.projects).toEqual([]);
496
509
  });
497
510
 
498
511
  test("parse maven tree", () => {