@cyclonedx/cdxgen 9.7.5 → 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 +35 -39
- package/bin/cdxgen.js +3 -0
- package/binary.js +29 -2
- package/data/lic-mapping.json +17 -1
- package/index.js +50 -54
- package/package.json +7 -6
- package/utils.js +538 -401
- package/utils.test.js +214 -50
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
|
|
|
@@ -31,7 +30,7 @@ A typical application might comprise of several repos, components, and libraries
|
|
|
31
30
|
| dart | pubspec.lock, pubspec.yaml | Only for pubspec.lock |
|
|
32
31
|
| haskell | cabal.project.freeze | Yes |
|
|
33
32
|
| elixir | mix.lock | Yes |
|
|
34
|
-
| c/c++
|
|
33
|
+
| c/c++/Objective C/c++11 | conan.lock, conanfile.txt, \*.cmake, CMakeLists.txt, meson.build, codebase without package managers! | Yes only for conan.lock. Best effort basis for cmake without version numbers. |
|
|
35
34
|
| clojure | Clojure CLI (deps.edn), Leiningen (project.clj) | Yes unless the files are parsed manually due to lack of clojure cli or leiningen command |
|
|
36
35
|
| swift | Package.resolved, Package.swift (swiftpm) | Yes |
|
|
37
36
|
| docker / oci image | All supported languages. Linux OS packages with plugins [4] | Best effort based on lock files |
|
|
@@ -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
|
|
@@ -147,6 +145,7 @@ $ cdxgen -h
|
|
|
147
145
|
--project-version Dependency track project version [default: ""]
|
|
148
146
|
--project-id Dependency track project id. Either provide the i
|
|
149
147
|
d or the project name and version together
|
|
148
|
+
--parent-project-id Dependency track parent project id
|
|
150
149
|
--required-only Include only the packages with required scope on
|
|
151
150
|
the SBoM. [boolean]
|
|
152
151
|
--fail-on-error Fail if any dependency extractor fails. [boolean]
|
|
@@ -174,7 +173,7 @@ $ cdxgen -h
|
|
|
174
173
|
-v, --version Show version number [boolean]
|
|
175
174
|
```
|
|
176
175
|
|
|
177
|
-
All boolean arguments
|
|
176
|
+
All boolean arguments accept `--no` prefix to toggle the behavior.
|
|
178
177
|
|
|
179
178
|
## Example
|
|
180
179
|
|
|
@@ -184,7 +183,7 @@ Minimal example.
|
|
|
184
183
|
cdxgen -o bom.json
|
|
185
184
|
```
|
|
186
185
|
|
|
187
|
-
For a java project.
|
|
186
|
+
For a java project. cdxgen would automatically detect maven, gradle, or sbt and build bom accordingly
|
|
188
187
|
|
|
189
188
|
```shell
|
|
190
189
|
cdxgen -t java -o bom.json
|
|
@@ -202,7 +201,7 @@ To recursively generate a single BoM for all languages pass `-r` argument.
|
|
|
202
201
|
cdxgen -r -o bom.json
|
|
203
202
|
```
|
|
204
203
|
|
|
205
|
-
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.
|
|
206
205
|
|
|
207
206
|
```shell
|
|
208
207
|
cdxgen -r -o bom.json --spec-version 1.4
|
|
@@ -215,15 +214,15 @@ To generate SBoM for C or Python, ensure Java >= 17 is installed.
|
|
|
215
214
|
cdxgen -t c -o bom.json
|
|
216
215
|
```
|
|
217
216
|
|
|
218
|
-
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.
|
|
219
218
|
|
|
220
219
|
## Universal SBoM
|
|
221
220
|
|
|
222
|
-
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.
|
|
223
222
|
|
|
224
223
|
## SBoM server
|
|
225
224
|
|
|
226
|
-
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`.
|
|
227
226
|
|
|
228
227
|
```shell
|
|
229
228
|
cdxgen --server
|
|
@@ -235,7 +234,7 @@ Or use the container image.
|
|
|
235
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
|
|
236
235
|
```
|
|
237
236
|
|
|
238
|
-
Use curl or your
|
|
237
|
+
Use curl or your favorite tool to pass arguments to the `/sbom` route.
|
|
239
238
|
|
|
240
239
|
### Scanning a local path
|
|
241
240
|
|
|
@@ -273,7 +272,7 @@ cdxgen app.war
|
|
|
273
272
|
|
|
274
273
|
## Resolving class names
|
|
275
274
|
|
|
276
|
-
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.
|
|
277
276
|
|
|
278
277
|
```shell
|
|
279
278
|
cdxgen -t java --resolve-class -o bom.json
|
|
@@ -283,7 +282,7 @@ This would create a bom.json.map file with the jar - class name mapping. Refer t
|
|
|
283
282
|
|
|
284
283
|
## Resolving licenses
|
|
285
284
|
|
|
286
|
-
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.
|
|
287
286
|
|
|
288
287
|
```bash
|
|
289
288
|
export FETCH_LICENSE=true
|
|
@@ -300,6 +299,7 @@ cdxgen can retain the dependency tree under the `dependencies` attribute for a s
|
|
|
300
299
|
- Gradle
|
|
301
300
|
- Scala SBT
|
|
302
301
|
- Python (requirements.txt, setup.py, pyproject.toml, poetry.lock)
|
|
302
|
+
- csharp (projects.assets.json)
|
|
303
303
|
|
|
304
304
|
## Environment variables
|
|
305
305
|
|
|
@@ -369,15 +369,11 @@ podman save -q --format oci-archive -o /tmp/slim.tar shiftleft/scan-slim
|
|
|
369
369
|
cdxgen /tmp/slim.tar -o /tmp/bom.json -t docker
|
|
370
370
|
```
|
|
371
371
|
|
|
372
|
-
NOTE:
|
|
373
|
-
|
|
374
|
-
- Only application related packages are collected by cdxgen. Support for OS installed packages is coming soon.
|
|
375
|
-
|
|
376
372
|
### Podman in rootless mode
|
|
377
373
|
|
|
378
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
|
|
379
375
|
|
|
380
|
-
|
|
376
|
+
Do not forget to start the podman socket required for API access on Linux.
|
|
381
377
|
|
|
382
378
|
```shell
|
|
383
379
|
systemctl --user enable --now podman.socket
|
|
@@ -395,27 +391,27 @@ obom
|
|
|
395
391
|
# cdxgen -t os
|
|
396
392
|
```
|
|
397
393
|
|
|
398
|
-
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.
|
|
399
395
|
|
|
400
396
|
## Generating SaaSBoM and component evidences
|
|
401
397
|
|
|
402
398
|
See [evinse mode](./ADVANCED.md) in the advanced documentation.
|
|
403
399
|
|
|
404
|
-
##
|
|
400
|
+
## BoM signing
|
|
405
401
|
|
|
406
|
-
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.
|
|
407
403
|
|
|
408
404
|
- SBOM_SIGN_ALGORITHM: Algorithm. Example: RS512
|
|
409
405
|
- SBOM_SIGN_PRIVATE_KEY: Location to the RSA private key
|
|
410
406
|
- SBOM_SIGN_PUBLIC_KEY: Optional. Location to the RSA public key
|
|
411
407
|
|
|
412
|
-
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.
|
|
413
409
|
|
|
414
410
|

|
|
415
411
|
|
|
416
412
|
### Verifying the signature
|
|
417
413
|
|
|
418
|
-
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.
|
|
419
415
|
|
|
420
416
|
```shell
|
|
421
417
|
npm install -g @cyclonedx/cdxgen
|
|
@@ -447,7 +443,7 @@ if (validationResult) {
|
|
|
447
443
|
|
|
448
444
|
## Automatic services detection
|
|
449
445
|
|
|
450
|
-
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.
|
|
451
447
|
|
|
452
448
|
## Conversion to SPDX format
|
|
453
449
|
|
|
@@ -470,7 +466,7 @@ Minimal example:
|
|
|
470
466
|
import { createBom, submitBom } from "npm:@cyclonedx/cdxgen@^9.0.1";
|
|
471
467
|
```
|
|
472
468
|
|
|
473
|
-
See the [Deno Readme](./contrib/deno/README.md) for detailed
|
|
469
|
+
See the [Deno Readme](./contrib/deno/README.md) for detailed instructions.
|
|
474
470
|
|
|
475
471
|
```javascript
|
|
476
472
|
import { createBom, submitBom } from "@cyclonedx/cdxgen";
|
|
@@ -486,7 +482,7 @@ Refer to the [permissions document](./docs/PERMISSIONS.md)
|
|
|
486
482
|
|
|
487
483
|
## Contributing
|
|
488
484
|
|
|
489
|
-
Follow the usual PR process but
|
|
485
|
+
Follow the usual PR process, but before raising a PR, run the following commands.
|
|
490
486
|
|
|
491
487
|
```bash
|
|
492
488
|
npm run lint
|
|
@@ -496,4 +492,4 @@ npm test
|
|
|
496
492
|
|
|
497
493
|
## Enterprise support
|
|
498
494
|
|
|
499
|
-
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/bin/cdxgen.js
CHANGED
|
@@ -73,6 +73,9 @@ const args = yargs(hideBin(process.argv))
|
|
|
73
73
|
description:
|
|
74
74
|
"Dependency track project id. Either provide the id or the project name and version together"
|
|
75
75
|
})
|
|
76
|
+
.option("parent-project-id", {
|
|
77
|
+
description: "Dependency track parent project id"
|
|
78
|
+
})
|
|
76
79
|
.option("required-only", {
|
|
77
80
|
type: "boolean",
|
|
78
81
|
description: "Include only the packages with required scope on the SBoM."
|
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
|
@@ -97,7 +97,9 @@ import {
|
|
|
97
97
|
addEvidenceForImports,
|
|
98
98
|
parseSbtTree,
|
|
99
99
|
parseCmakeLikeFile,
|
|
100
|
-
getCppModules
|
|
100
|
+
getCppModules,
|
|
101
|
+
FETCH_LICENSE,
|
|
102
|
+
getNugetMetadata
|
|
101
103
|
} from "./utils.js";
|
|
102
104
|
import { spawnSync } from "node:child_process";
|
|
103
105
|
import { fileURLToPath } from "node:url";
|
|
@@ -653,8 +655,8 @@ function addComponent(
|
|
|
653
655
|
}
|
|
654
656
|
if (!isRootPkg) {
|
|
655
657
|
const pkgIdentifier = parsePackageJsonName(pkg.name);
|
|
656
|
-
const author = pkg.author ||
|
|
657
|
-
const publisher = pkg.publisher ||
|
|
658
|
+
const author = pkg.author || undefined;
|
|
659
|
+
const publisher = pkg.publisher || undefined;
|
|
658
660
|
let group = pkg.group || pkgIdentifier.scope;
|
|
659
661
|
// Create empty group
|
|
660
662
|
group = group || "";
|
|
@@ -682,7 +684,7 @@ function addComponent(
|
|
|
682
684
|
purlString = decodeURIComponent(purlString);
|
|
683
685
|
let description = { "#cdata": pkg.description };
|
|
684
686
|
if (format === "json") {
|
|
685
|
-
description = pkg.description ||
|
|
687
|
+
description = pkg.description || undefined;
|
|
686
688
|
}
|
|
687
689
|
let compScope = pkg.scope;
|
|
688
690
|
if (allImports) {
|
|
@@ -1265,7 +1267,7 @@ export const createJavaBom = async (path, options) => {
|
|
|
1265
1267
|
);
|
|
1266
1268
|
} else {
|
|
1267
1269
|
console.log(
|
|
1268
|
-
"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."
|
|
1269
1271
|
);
|
|
1270
1272
|
}
|
|
1271
1273
|
console.log(
|
|
@@ -2983,7 +2985,13 @@ export const createCppBom = (path, options) => {
|
|
|
2983
2985
|
}
|
|
2984
2986
|
}
|
|
2985
2987
|
}
|
|
2986
|
-
|
|
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
|
+
) {
|
|
2987
2995
|
let osPkgsList = [];
|
|
2988
2996
|
// Case 1: Development libraries installed in this OS environment might be used for build
|
|
2989
2997
|
// We collect OS packages with the word dev in the name using osquery here
|
|
@@ -3010,10 +3018,12 @@ export const createCppBom = (path, options) => {
|
|
|
3010
3018
|
pkgList = pkgList.concat(dlist);
|
|
3011
3019
|
}
|
|
3012
3020
|
}
|
|
3013
|
-
if (!
|
|
3014
|
-
|
|
3021
|
+
if (!options.createMultiXBom) {
|
|
3022
|
+
if (!parentComponent) {
|
|
3023
|
+
parentComponent = createDefaultParentComponent(path, "conan", options);
|
|
3024
|
+
}
|
|
3025
|
+
options.parentComponent = parentComponent;
|
|
3015
3026
|
}
|
|
3016
|
-
options.parentComponent = parentComponent;
|
|
3017
3027
|
return buildBomNSData(options, pkgList, "conan", {
|
|
3018
3028
|
src: path,
|
|
3019
3029
|
parentComponent
|
|
@@ -3913,39 +3923,17 @@ export const createRubyBom = async (path, options) => {
|
|
|
3913
3923
|
return {};
|
|
3914
3924
|
};
|
|
3915
3925
|
|
|
3916
|
-
const removeDuplicates = (pkgList, dependencies) => {
|
|
3917
|
-
const uniqueItems = {};
|
|
3918
|
-
const uniqueRefs = new Set();
|
|
3919
|
-
const newPkgList = [];
|
|
3920
|
-
const newDependencies = [];
|
|
3921
|
-
|
|
3922
|
-
for (const item of pkgList) {
|
|
3923
|
-
if (item) {
|
|
3924
|
-
const { name, version } = item;
|
|
3925
|
-
const key = `${name}-${version}`;
|
|
3926
|
-
if (!uniqueItems[key] && key) {
|
|
3927
|
-
uniqueItems[key] = item;
|
|
3928
|
-
newPkgList.push(item);
|
|
3929
|
-
}
|
|
3930
|
-
}
|
|
3931
|
-
}
|
|
3932
|
-
|
|
3933
|
-
for (const item of dependencies) {
|
|
3934
|
-
const { ref } = item;
|
|
3935
|
-
if (!uniqueRefs.has(ref)) {
|
|
3936
|
-
uniqueRefs.add(ref);
|
|
3937
|
-
newDependencies.push(item);
|
|
3938
|
-
}
|
|
3939
|
-
}
|
|
3940
|
-
return [newPkgList, newDependencies];
|
|
3941
|
-
};
|
|
3942
3926
|
/**
|
|
3943
3927
|
* Function to create bom string for csharp projects
|
|
3944
3928
|
*
|
|
3945
3929
|
* @param path to the project
|
|
3946
3930
|
* @param options Parse options from the cli
|
|
3947
3931
|
*/
|
|
3948
|
-
export const createCsharpBom = async (
|
|
3932
|
+
export const createCsharpBom = async (
|
|
3933
|
+
path,
|
|
3934
|
+
options,
|
|
3935
|
+
parentComponent = undefined
|
|
3936
|
+
) => {
|
|
3949
3937
|
let manifestFiles = [];
|
|
3950
3938
|
let pkgData = undefined;
|
|
3951
3939
|
let dependencies = [];
|
|
@@ -3970,7 +3958,7 @@ export const createCsharpBom = async (path, options) => {
|
|
|
3970
3958
|
(options.multiProject ? "**/" : "") + "*.nupkg"
|
|
3971
3959
|
);
|
|
3972
3960
|
let pkgList = [];
|
|
3973
|
-
if (nupkgFiles.length) {
|
|
3961
|
+
if (nupkgFiles.length && projAssetsFiles.length === 0) {
|
|
3974
3962
|
manifestFiles = manifestFiles.concat(nupkgFiles);
|
|
3975
3963
|
for (const nf of nupkgFiles) {
|
|
3976
3964
|
if (DEBUG_MODE) {
|
|
@@ -4048,17 +4036,27 @@ export const createCsharpBom = async (path, options) => {
|
|
|
4048
4036
|
}
|
|
4049
4037
|
}
|
|
4050
4038
|
}
|
|
4039
|
+
if (!parentComponent) {
|
|
4040
|
+
parentComponent = createDefaultParentComponent(path, options.type, options);
|
|
4041
|
+
}
|
|
4051
4042
|
if (pkgList.length) {
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
pkgList = uniquePkg[0];
|
|
4055
|
-
return buildBomNSData(options, pkgList, "nuget", {
|
|
4056
|
-
src: path,
|
|
4057
|
-
filename: manifestFiles.join(", "),
|
|
4058
|
-
dependencies
|
|
4059
|
-
});
|
|
4043
|
+
dependencies = mergeDependencies(dependencies, [], parentComponent);
|
|
4044
|
+
pkgList = trimComponents(pkgList, "json");
|
|
4060
4045
|
}
|
|
4061
|
-
|
|
4046
|
+
if (FETCH_LICENSE) {
|
|
4047
|
+
const retMap = await getNugetMetadata(pkgList, dependencies);
|
|
4048
|
+
if (retMap.dependencies && retMap.dependencies.length) {
|
|
4049
|
+
dependencies = dependencies.concat(retMap.dependencies);
|
|
4050
|
+
}
|
|
4051
|
+
dependencies = mergeDependencies(dependencies, [], parentComponent);
|
|
4052
|
+
pkgList = trimComponents(pkgList, "json");
|
|
4053
|
+
}
|
|
4054
|
+
return buildBomNSData(options, pkgList, "nuget", {
|
|
4055
|
+
src: path,
|
|
4056
|
+
filename: manifestFiles.join(", "),
|
|
4057
|
+
dependencies,
|
|
4058
|
+
parentComponent
|
|
4059
|
+
});
|
|
4062
4060
|
};
|
|
4063
4061
|
|
|
4064
4062
|
export const mergeDependencies = (
|
|
@@ -4180,6 +4178,7 @@ export const createMultiXBom = async (pathList, options) => {
|
|
|
4180
4178
|
let bomData = undefined;
|
|
4181
4179
|
let parentComponent = determineParentComponent(options) || {};
|
|
4182
4180
|
let parentSubComponents = [];
|
|
4181
|
+
options.createMultiXBom = true;
|
|
4183
4182
|
if (
|
|
4184
4183
|
["docker", "oci", "container"].includes(options.projectType) &&
|
|
4185
4184
|
options.allLayersExplodedDir
|
|
@@ -4404,7 +4403,7 @@ export const createMultiXBom = async (pathList, options) => {
|
|
|
4404
4403
|
listComponents(options, {}, bomData.bomJson.components, "gem", "xml")
|
|
4405
4404
|
);
|
|
4406
4405
|
}
|
|
4407
|
-
bomData = await createCsharpBom(path, options);
|
|
4406
|
+
bomData = await createCsharpBom(path, options, parentComponent);
|
|
4408
4407
|
if (bomData && bomData.bomJson && bomData.bomJson.components) {
|
|
4409
4408
|
if (DEBUG_MODE) {
|
|
4410
4409
|
console.log(
|
|
@@ -5229,6 +5228,9 @@ export async function submitBom(args, bomContents) {
|
|
|
5229
5228
|
autoCreate: "true",
|
|
5230
5229
|
bom: encodedBomContents
|
|
5231
5230
|
};
|
|
5231
|
+
if (typeof args.parentProjectId !== "undefined") {
|
|
5232
|
+
bomPayload.parentUUID = args.parentProjectId;
|
|
5233
|
+
}
|
|
5232
5234
|
if (DEBUG_MODE) {
|
|
5233
5235
|
console.log(
|
|
5234
5236
|
"Submitting BOM to",
|
|
@@ -5265,13 +5267,7 @@ export async function submitBom(args, bomContents) {
|
|
|
5265
5267
|
"Content-Type": "application/json",
|
|
5266
5268
|
"user-agent": `@CycloneDX/cdxgen ${_version}`
|
|
5267
5269
|
},
|
|
5268
|
-
json:
|
|
5269
|
-
project: args.projectId,
|
|
5270
|
-
projectName: args.projectName,
|
|
5271
|
-
projectVersion: projectVersion,
|
|
5272
|
-
autoCreate: "true",
|
|
5273
|
-
bom: encodedBomContents
|
|
5274
|
-
},
|
|
5270
|
+
json: bomPayload,
|
|
5275
5271
|
responseType: "json"
|
|
5276
5272
|
}).json();
|
|
5277
5273
|
} catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyclonedx/cdxgen",
|
|
3
|
-
"version": "9.
|
|
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>",
|
|
@@ -55,7 +55,8 @@
|
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@babel/parser": "^7.22.16",
|
|
58
|
-
"@babel/traverse": "^7.22.
|
|
58
|
+
"@babel/traverse": "^7.22.19",
|
|
59
|
+
"@npmcli/arborist": "^7.1.0",
|
|
59
60
|
"ajv": "^8.12.0",
|
|
60
61
|
"ajv-formats": "^2.1.1",
|
|
61
62
|
"cheerio": "^1.0.0-rc.12",
|
|
@@ -74,13 +75,13 @@
|
|
|
74
75
|
"ssri": "^10.0.4",
|
|
75
76
|
"table": "^6.8.1",
|
|
76
77
|
"tar": "^6.2.0",
|
|
77
|
-
"uuid": "^9.0.
|
|
78
|
+
"uuid": "^9.0.1",
|
|
78
79
|
"xml-js": "^1.6.11",
|
|
79
80
|
"xmlbuilder": "^15.1.1",
|
|
80
81
|
"yargs": "^17.7.2"
|
|
81
82
|
},
|
|
82
83
|
"optionalDependencies": {
|
|
83
|
-
"@appthreat/atom": "^1.
|
|
84
|
+
"@appthreat/atom": "^1.2.0",
|
|
84
85
|
"@cyclonedx/cdxgen-plugins-bin": "^1.4.0",
|
|
85
86
|
"@cyclonedx/cdxgen-plugins-bin-arm64": "^1.4.0",
|
|
86
87
|
"@cyclonedx/cdxgen-plugins-bin-ppc64": "^1.4.0",
|
|
@@ -98,8 +99,8 @@
|
|
|
98
99
|
],
|
|
99
100
|
"devDependencies": {
|
|
100
101
|
"caxa": "^3.0.1",
|
|
101
|
-
"eslint": "^8.
|
|
102
|
-
"jest": "^29.
|
|
102
|
+
"eslint": "^8.49.0",
|
|
103
|
+
"jest": "^29.7.0",
|
|
103
104
|
"prettier": "3.0.3"
|
|
104
105
|
}
|
|
105
106
|
}
|