@cyclonedx/cdxgen 8.0.3 → 8.0.5
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 +29 -25
- package/bin/cdxgen +4 -1
- package/index.js +0 -7
- package/package.json +5 -5
- package/utils.js +28 -24
package/README.md
CHANGED
|
@@ -71,19 +71,19 @@ For go, `go mod why` command is used to identify required packages. For php, com
|
|
|
71
71
|
|
|
72
72
|
## Installing
|
|
73
73
|
|
|
74
|
-
```
|
|
74
|
+
```shell
|
|
75
75
|
sudo npm install -g @cyclonedx/cdxgen
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
You can also use the cdxgen container image
|
|
79
79
|
|
|
80
80
|
```bash
|
|
81
|
-
docker run --rm -
|
|
81
|
+
docker run --rm -v /tmp:/tmp -v $(pwd):/app:rw -t ghcr.io/cyclonedx/cdxgen -r /app -o /app/bom.json
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
## Getting Help
|
|
85
85
|
|
|
86
|
-
```
|
|
86
|
+
```text
|
|
87
87
|
$ cdxgen -h
|
|
88
88
|
Options:
|
|
89
89
|
-o, --output Output file for bom.xml or bom.json. Default console
|
|
@@ -122,7 +122,7 @@ Options:
|
|
|
122
122
|
|
|
123
123
|
Minimal example.
|
|
124
124
|
|
|
125
|
-
```
|
|
125
|
+
```shell
|
|
126
126
|
cdxgen -o bom.json
|
|
127
127
|
```
|
|
128
128
|
|
|
@@ -132,19 +132,19 @@ cdxgen would always produce bom in both xml and json format as per CycloneDX 1.4
|
|
|
132
132
|
|
|
133
133
|
For a java project. This would automatically detect maven, gradle or sbt and build bom accordingly
|
|
134
134
|
|
|
135
|
-
```
|
|
135
|
+
```shell
|
|
136
136
|
cdxgen -t java -o bom.json
|
|
137
137
|
```
|
|
138
138
|
|
|
139
139
|
To print the SBoM as a table pass `-p` argument.
|
|
140
140
|
|
|
141
|
-
```
|
|
141
|
+
```shell
|
|
142
142
|
cdxgen -t java -o bom.json -p
|
|
143
143
|
```
|
|
144
144
|
|
|
145
145
|
To recursively generate a single BoM for all languages pass `-r` argument.
|
|
146
146
|
|
|
147
|
-
```
|
|
147
|
+
```shell
|
|
148
148
|
cdxgen -r -o bom.json
|
|
149
149
|
```
|
|
150
150
|
|
|
@@ -156,27 +156,27 @@ By passing the type `-t universal`, cdxgen could be forced to opportunistically
|
|
|
156
156
|
|
|
157
157
|
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`.
|
|
158
158
|
|
|
159
|
-
```
|
|
159
|
+
```shell
|
|
160
160
|
cdxgen --server
|
|
161
161
|
```
|
|
162
162
|
|
|
163
163
|
Or use the container image.
|
|
164
164
|
|
|
165
165
|
```bash
|
|
166
|
-
docker run --rm -
|
|
166
|
+
docker run --rm -v /tmp:/tmp -p 9090:9090 -v $(pwd):/app:rw -t ghcr.io/cyclonedx/cdxgen -r /app --server
|
|
167
167
|
```
|
|
168
168
|
|
|
169
169
|
Use curl or your favourite tool to pass arguments to the `/sbom` route.
|
|
170
170
|
|
|
171
171
|
### Scanning a local path
|
|
172
172
|
|
|
173
|
-
```
|
|
173
|
+
```shell
|
|
174
174
|
curl "http://127.0.0.1:9090/sbom?path=/Volumes/Work/sandbox/vulnerable-aws-koa-app&multiProject=true&type=js"
|
|
175
175
|
```
|
|
176
176
|
|
|
177
177
|
### Scanning a git repo
|
|
178
178
|
|
|
179
|
-
```
|
|
179
|
+
```shell
|
|
180
180
|
curl "http://127.0.0.1:9090/sbom?url=https://github.com/HooliCorp/vulnerable-aws-koa-app.git&multiProject=true&type=js"
|
|
181
181
|
```
|
|
182
182
|
|
|
@@ -188,7 +188,7 @@ curl -H "Content-Type: application/json" http://localhost:9090/sbom -XPOST -d $'
|
|
|
188
188
|
|
|
189
189
|
### Docker compose
|
|
190
190
|
|
|
191
|
-
```
|
|
191
|
+
```shell
|
|
192
192
|
git clone https://github.com/cyclonedx/cdxgen.git
|
|
193
193
|
docker compose up
|
|
194
194
|
```
|
|
@@ -199,7 +199,7 @@ In universal mode, cdxgen can look for any [Privado](https://www.privado.ai?utm_
|
|
|
199
199
|
|
|
200
200
|
Invoke privado scan first to generate this report followed by an invocation of cdxgen in universal mode as shown.
|
|
201
201
|
|
|
202
|
-
```
|
|
202
|
+
```shell
|
|
203
203
|
privado scan --enable-javascript <directory>
|
|
204
204
|
cdxgen -t universal <directory> -o bom.json
|
|
205
205
|
```
|
|
@@ -208,7 +208,7 @@ cdxgen -t universal <directory> -o bom.json
|
|
|
208
208
|
|
|
209
209
|
cdxgen can generate a BoM file from a given war file.
|
|
210
210
|
|
|
211
|
-
```
|
|
211
|
+
```shell
|
|
212
212
|
# cdxgen -t java app.war
|
|
213
213
|
cdxgen app.war
|
|
214
214
|
```
|
|
@@ -217,7 +217,7 @@ cdxgen app.war
|
|
|
217
217
|
|
|
218
218
|
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.
|
|
219
219
|
|
|
220
|
-
```
|
|
220
|
+
```shell
|
|
221
221
|
cdxgen -t java --resolve-class -o bom.json
|
|
222
222
|
```
|
|
223
223
|
|
|
@@ -271,7 +271,7 @@ cdxgen can retain the dependency tree under the `dependencies` attribute for a s
|
|
|
271
271
|
|
|
272
272
|
cdxgen could be extended with external binary plugins to support more SBoM use cases. These are now installed as an optional dependency.
|
|
273
273
|
|
|
274
|
-
```
|
|
274
|
+
```shell
|
|
275
275
|
sudo npm install -g @cyclonedx/cdxgen-plugins-bin
|
|
276
276
|
```
|
|
277
277
|
|
|
@@ -279,19 +279,19 @@ sudo npm install -g @cyclonedx/cdxgen-plugins-bin
|
|
|
279
279
|
|
|
280
280
|
`docker` type is automatically detected based on the presence of values such as `sha256` or `docker.io` prefix etc in the path.
|
|
281
281
|
|
|
282
|
-
```
|
|
282
|
+
```shell
|
|
283
283
|
cdxgen odoo@sha256:4e1e147f0e6714e8f8c5806d2b484075b4076ca50490577cdf9162566086d15e -o /tmp/bom.json
|
|
284
284
|
```
|
|
285
285
|
|
|
286
286
|
You can also pass `-t docker` for simple labels. Only the `latest` tag would be pulled if none was specified.
|
|
287
287
|
|
|
288
|
-
```
|
|
288
|
+
```shell
|
|
289
289
|
cdxgen shiftleft/scan-slim -o /tmp/bom.json -t docker
|
|
290
290
|
```
|
|
291
291
|
|
|
292
292
|
You can also pass the .tar file of a container image.
|
|
293
293
|
|
|
294
|
-
```
|
|
294
|
+
```shell
|
|
295
295
|
docker save -o /tmp/slim.tar shiftleft/scan-slim
|
|
296
296
|
podman save -q --format oci-archive -o /tmp/slim.tar shiftleft/scan-slim
|
|
297
297
|
cdxgen /tmp/slim.tar -o /tmp/bom.json -t docker
|
|
@@ -307,7 +307,7 @@ Setup podman in either [rootless](https://github.com/containers/podman/blob/mast
|
|
|
307
307
|
|
|
308
308
|
On Linux, do not forget to start the podman socket which is required for API access.
|
|
309
309
|
|
|
310
|
-
```
|
|
310
|
+
```shell
|
|
311
311
|
systemctl --user enable --now podman.socket
|
|
312
312
|
systemctl --user start podman.socket
|
|
313
313
|
podman system service -t 0 &
|
|
@@ -317,7 +317,7 @@ podman system service -t 0 &
|
|
|
317
317
|
|
|
318
318
|
You can use cdxgen to generate SBoM for a live system or a VM for compliance and vulnerability management purposes by passing the argument `-t os`.
|
|
319
319
|
|
|
320
|
-
```
|
|
320
|
+
```shell
|
|
321
321
|
cdxgen -t os
|
|
322
322
|
```
|
|
323
323
|
|
|
@@ -348,10 +348,14 @@ Use the [CycloneDX CLI](https://github.com/CycloneDX/cyclonedx-cli) tool for adv
|
|
|
348
348
|
Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. See the [LICENSE](LICENSE) file for the full license.
|
|
349
349
|
|
|
350
350
|
[license]: https://github.com/cyclonedx/cdxgen/blob/master/LICENSE
|
|
351
|
+
[cyclonedx-homepage]: https://cyclonedx.org
|
|
351
352
|
|
|
352
|
-
##
|
|
353
|
-
|
|
354
|
-
The developers could be reached via the [discord](https://discord.gg/DCNxzaeUpd) channel.
|
|
353
|
+
## Contributing
|
|
355
354
|
|
|
355
|
+
Follow the usual PR process but prior to raising a PR run the following commands.
|
|
356
356
|
|
|
357
|
-
|
|
357
|
+
```bash
|
|
358
|
+
npm run lint
|
|
359
|
+
npm run pretty
|
|
360
|
+
npm test
|
|
361
|
+
```
|
package/bin/cdxgen
CHANGED
|
@@ -155,7 +155,10 @@ let options = {
|
|
|
155
155
|
}
|
|
156
156
|
const bomNSData = (await bom.createBom(filePath, options)) || {};
|
|
157
157
|
|
|
158
|
-
if (
|
|
158
|
+
if (
|
|
159
|
+
args.output &&
|
|
160
|
+
(typeof args.output === "string" || args.output instanceof String)
|
|
161
|
+
) {
|
|
159
162
|
if (bomNSData.bomXmlFiles) {
|
|
160
163
|
console.log("BOM files produced:", bomNSData.bomXmlFiles);
|
|
161
164
|
} else {
|
package/index.js
CHANGED
|
@@ -1681,13 +1681,6 @@ const createNodejsBom = async (path, options) => {
|
|
|
1681
1681
|
);
|
|
1682
1682
|
}
|
|
1683
1683
|
}
|
|
1684
|
-
return buildBomNSData(options, pkgList, "npm", {
|
|
1685
|
-
allImports,
|
|
1686
|
-
src: path,
|
|
1687
|
-
filename: manifestFiles.join(", "),
|
|
1688
|
-
dependencies,
|
|
1689
|
-
parentComponent
|
|
1690
|
-
});
|
|
1691
1684
|
}
|
|
1692
1685
|
if (pkgLockFiles && pkgLockFiles.length) {
|
|
1693
1686
|
manifestFiles = manifestFiles.concat(pkgLockFiles);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyclonedx/cdxgen",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.5",
|
|
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>",
|
|
@@ -49,11 +49,11 @@
|
|
|
49
49
|
"url": "https://github.com/cyclonedx/cdxgen/issues"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@babel/parser": "^7.20.
|
|
53
|
-
"@babel/traverse": "^7.20.
|
|
52
|
+
"@babel/parser": "^7.20.15",
|
|
53
|
+
"@babel/traverse": "^7.20.13",
|
|
54
54
|
"cheerio": "^1.0.0-rc.12",
|
|
55
55
|
"edn-data": "^1.0.0",
|
|
56
|
-
"glob": "^8.0
|
|
56
|
+
"glob": "^8.1.0",
|
|
57
57
|
"global-agent": "^3.0.0",
|
|
58
58
|
"got": "^11.8.5",
|
|
59
59
|
"js-yaml": "^4.1.0",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"yargs": "^17.6.2"
|
|
74
74
|
},
|
|
75
75
|
"optionalDependencies": {
|
|
76
|
-
"@cyclonedx/cdxgen-plugins-bin": "^1.0.
|
|
76
|
+
"@cyclonedx/cdxgen-plugins-bin": "^1.0.5",
|
|
77
77
|
"connect": "^3.7.0",
|
|
78
78
|
"body-parser": "^1.20.1",
|
|
79
79
|
"compression": "^1.7.4"
|
package/utils.js
CHANGED
|
@@ -36,6 +36,18 @@ const MAX_LICENSE_ID_LENGTH = 100;
|
|
|
36
36
|
*/
|
|
37
37
|
const getAllFiles = function (dirPath, pattern) {
|
|
38
38
|
try {
|
|
39
|
+
const ignoreList = [
|
|
40
|
+
"**/.hg/**",
|
|
41
|
+
"**/.git/**",
|
|
42
|
+
"**/venv/**",
|
|
43
|
+
"**/docs/**",
|
|
44
|
+
"**/examples/**",
|
|
45
|
+
"**/site-packages/**"
|
|
46
|
+
];
|
|
47
|
+
// Only ignore node_modules if the caller is not looking for package.json
|
|
48
|
+
if (!pattern.includes("package.json")) {
|
|
49
|
+
ignoreList.push("**/node_modules/**");
|
|
50
|
+
}
|
|
39
51
|
return glob.sync(pattern, {
|
|
40
52
|
cwd: dirPath,
|
|
41
53
|
silent: true,
|
|
@@ -45,15 +57,7 @@ const getAllFiles = function (dirPath, pattern) {
|
|
|
45
57
|
strict: true,
|
|
46
58
|
dot: pattern.startsWith(".") ? true : false,
|
|
47
59
|
follow: false,
|
|
48
|
-
ignore:
|
|
49
|
-
"node_modules",
|
|
50
|
-
".hg",
|
|
51
|
-
".git",
|
|
52
|
-
"venv",
|
|
53
|
-
"docs",
|
|
54
|
-
"examples",
|
|
55
|
-
"site-packages"
|
|
56
|
-
]
|
|
60
|
+
ignore: ignoreList
|
|
57
61
|
});
|
|
58
62
|
} catch (err) {
|
|
59
63
|
if (DEBUG_MODE) {
|
|
@@ -327,10 +331,10 @@ const parsePkgJson = async (pkgJsonFile) => {
|
|
|
327
331
|
// continue regardless of error
|
|
328
332
|
}
|
|
329
333
|
}
|
|
330
|
-
if (process.env.FETCH_LICENSE) {
|
|
334
|
+
if (process.env.FETCH_LICENSE && pkgList && pkgList.length) {
|
|
331
335
|
if (DEBUG_MODE) {
|
|
332
336
|
console.log(
|
|
333
|
-
`About to fetch license information for ${pkgList.length} packages`
|
|
337
|
+
`About to fetch license information for ${pkgList.length} packages in parsePkgJson`
|
|
334
338
|
);
|
|
335
339
|
}
|
|
336
340
|
return await getNpmMetadata(pkgList);
|
|
@@ -432,10 +436,10 @@ const parsePkgLock = async (pkgLockFile) => {
|
|
|
432
436
|
lockData
|
|
433
437
|
);
|
|
434
438
|
}
|
|
435
|
-
if (process.env.FETCH_LICENSE) {
|
|
439
|
+
if (process.env.FETCH_LICENSE && pkgList && pkgList.length) {
|
|
436
440
|
if (DEBUG_MODE) {
|
|
437
441
|
console.log(
|
|
438
|
-
`About to fetch license information for ${pkgList.length} packages`
|
|
442
|
+
`About to fetch license information for ${pkgList.length} packages in parsePkgLock`
|
|
439
443
|
);
|
|
440
444
|
}
|
|
441
445
|
pkgList = await getNpmMetadata(pkgList);
|
|
@@ -481,7 +485,7 @@ const yarnLockToIdentMap = function (lockData) {
|
|
|
481
485
|
if (group) {
|
|
482
486
|
group = `${group}/`;
|
|
483
487
|
}
|
|
484
|
-
if (range.startsWith("npm:")) {
|
|
488
|
+
if (range && range.startsWith("npm:")) {
|
|
485
489
|
range = range.replace("npm:", "");
|
|
486
490
|
}
|
|
487
491
|
currentIdents.push(`${group || ""}${name}@${range}`);
|
|
@@ -638,10 +642,10 @@ const parseYarnLock = async function (yarnLockFile) {
|
|
|
638
642
|
}
|
|
639
643
|
});
|
|
640
644
|
}
|
|
641
|
-
if (process.env.FETCH_LICENSE) {
|
|
645
|
+
if (process.env.FETCH_LICENSE && pkgList && pkgList.length) {
|
|
642
646
|
if (DEBUG_MODE) {
|
|
643
647
|
console.log(
|
|
644
|
-
`About to fetch license information for ${pkgList.length} packages`
|
|
648
|
+
`About to fetch license information for ${pkgList.length} packages in parseYarnLock`
|
|
645
649
|
);
|
|
646
650
|
}
|
|
647
651
|
pkgList = await getNpmMetadata(pkgList);
|
|
@@ -705,10 +709,10 @@ const parseNodeShrinkwrap = async function (swFile) {
|
|
|
705
709
|
}
|
|
706
710
|
}
|
|
707
711
|
}
|
|
708
|
-
if (process.env.FETCH_LICENSE) {
|
|
712
|
+
if (process.env.FETCH_LICENSE && pkgList && pkgList.length) {
|
|
709
713
|
if (DEBUG_MODE) {
|
|
710
714
|
console.log(
|
|
711
|
-
`About to fetch license information for ${pkgList.length} packages`
|
|
715
|
+
`About to fetch license information for ${pkgList.length} packages in parseNodeShrinkwrap`
|
|
712
716
|
);
|
|
713
717
|
}
|
|
714
718
|
return await getNpmMetadata(pkgList);
|
|
@@ -827,10 +831,10 @@ const parsePnpmLock = async function (pnpmLock, parentComponent = null) {
|
|
|
827
831
|
}
|
|
828
832
|
}
|
|
829
833
|
}
|
|
830
|
-
if (process.env.FETCH_LICENSE) {
|
|
834
|
+
if (process.env.FETCH_LICENSE && pkgList && pkgList.length) {
|
|
831
835
|
if (DEBUG_MODE) {
|
|
832
836
|
console.log(
|
|
833
|
-
`About to fetch license information for ${pkgList.length} packages`
|
|
837
|
+
`About to fetch license information for ${pkgList.length} packages in parsePnpmLock`
|
|
834
838
|
);
|
|
835
839
|
}
|
|
836
840
|
pkgList = await getNpmMetadata(pkgList);
|
|
@@ -874,10 +878,10 @@ const parseBowerJson = async (bowerJsonFile) => {
|
|
|
874
878
|
// continue regardless of error
|
|
875
879
|
}
|
|
876
880
|
}
|
|
877
|
-
if (process.env.FETCH_LICENSE) {
|
|
881
|
+
if (process.env.FETCH_LICENSE && pkgList && pkgList.length) {
|
|
878
882
|
if (DEBUG_MODE) {
|
|
879
883
|
console.log(
|
|
880
|
-
`About to fetch license information for ${pkgList.length} packages`
|
|
884
|
+
`About to fetch license information for ${pkgList.length} packages in parseBowerJson`
|
|
881
885
|
);
|
|
882
886
|
}
|
|
883
887
|
return await getNpmMetadata(pkgList);
|
|
@@ -948,10 +952,10 @@ const parseMinJs = async (minJsFile) => {
|
|
|
948
952
|
// continue regardless of error
|
|
949
953
|
}
|
|
950
954
|
}
|
|
951
|
-
if (process.env.FETCH_LICENSE) {
|
|
955
|
+
if (process.env.FETCH_LICENSE && pkgList && pkgList.length) {
|
|
952
956
|
if (DEBUG_MODE) {
|
|
953
957
|
console.log(
|
|
954
|
-
`About to fetch license information for ${pkgList.length} packages`
|
|
958
|
+
`About to fetch license information for ${pkgList.length} packages in parseMinJs`
|
|
955
959
|
);
|
|
956
960
|
}
|
|
957
961
|
return await getNpmMetadata(pkgList);
|