@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 +33 -38
- package/binary.js +29 -2
- package/data/lic-mapping.json +17 -1
- package/index.js +17 -8
- package/package.json +1 -1
- package/utils.js +43 -10
- package/utils.test.js +13 -0
package/README.md
CHANGED
|
@@ -2,17 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
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
|
|
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+
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
##
|
|
400
|
+
## BoM signing
|
|
406
401
|
|
|
407
|
-
cdxgen can sign the generated
|
|
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
|
|
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
|

|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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 (
|
package/data/lic-mapping.json
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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 (!
|
|
3016
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
|
|
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", () => {
|