@cyclonedx/cdxgen 9.3.1 → 9.4.0
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 +82 -3
- package/bin/cdxgen.js +22 -1
- package/bin/repl.js +311 -0
- package/display.js +3 -0
- package/docker.js +1 -1
- package/docker.test.js +8 -5
- package/index.js +88 -41
- package/package.json +13 -10
- package/piptree.js +2 -2
- package/utils.js +144 -48
- package/utils.test.js +29 -10
package/index.js
CHANGED
|
@@ -199,18 +199,25 @@ const createDefaultParentComponent = (path, type = "application") => {
|
|
|
199
199
|
|
|
200
200
|
const determineParentComponent = (options) => {
|
|
201
201
|
let parentComponent = undefined;
|
|
202
|
-
if (options.
|
|
202
|
+
if (options.parentComponent && Object.keys(options.parentComponent).length) {
|
|
203
|
+
return options.parentComponent;
|
|
204
|
+
} else if (options.projectName && options.projectVersion) {
|
|
203
205
|
parentComponent = {
|
|
204
206
|
group: options.projectGroup || "",
|
|
205
207
|
name: options.projectName,
|
|
206
208
|
version: "" + options.projectVersion || "",
|
|
207
209
|
type: "application"
|
|
208
210
|
};
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
211
|
+
const ppurl = new PackageURL(
|
|
212
|
+
parentComponent.type,
|
|
213
|
+
parentComponent.group,
|
|
214
|
+
parentComponent.name,
|
|
215
|
+
parentComponent.version,
|
|
216
|
+
null,
|
|
217
|
+
null
|
|
218
|
+
).toString();
|
|
219
|
+
parentComponent["bom-ref"] = ppurl;
|
|
220
|
+
parentComponent["purl"] = decodeURIComponent(ppurl);
|
|
214
221
|
}
|
|
215
222
|
return parentComponent;
|
|
216
223
|
};
|
|
@@ -323,11 +330,18 @@ function addMetadata(parentComponent = {}, format = "xml", options = {}) {
|
|
|
323
330
|
if (parentComponent) {
|
|
324
331
|
delete parentComponent.evidence;
|
|
325
332
|
delete parentComponent._integrity;
|
|
333
|
+
delete parentComponent.license;
|
|
334
|
+
if (!parentComponent["purl"] && parentComponent["bom-ref"]) {
|
|
335
|
+
parentComponent["purl"] = decodeURIComponent(
|
|
336
|
+
parentComponent["bom-ref"]
|
|
337
|
+
);
|
|
338
|
+
}
|
|
326
339
|
}
|
|
327
340
|
if (parentComponent && parentComponent.components) {
|
|
328
341
|
for (const comp of parentComponent.components) {
|
|
329
342
|
delete comp.evidence;
|
|
330
343
|
delete comp._integrity;
|
|
344
|
+
delete comp.license;
|
|
331
345
|
if (!comp["bom-ref"] && comp.name && comp.type) {
|
|
332
346
|
let fullName =
|
|
333
347
|
comp.group && comp.group.length
|
|
@@ -1216,7 +1230,8 @@ export const createJavaBom = async (path, options) => {
|
|
|
1216
1230
|
if (bomJsonObj.dependencies && !options.requiredOnly) {
|
|
1217
1231
|
dependencies = mergeDependencies(
|
|
1218
1232
|
dependencies,
|
|
1219
|
-
bomJsonObj.dependencies
|
|
1233
|
+
bomJsonObj.dependencies,
|
|
1234
|
+
parentComponent
|
|
1220
1235
|
);
|
|
1221
1236
|
}
|
|
1222
1237
|
}
|
|
@@ -1335,16 +1350,21 @@ export const createJavaBom = async (path, options) => {
|
|
|
1335
1350
|
let gradleDepArgs = [
|
|
1336
1351
|
sp.purl === parentComponent.purl
|
|
1337
1352
|
? depTaskWithArgs[0]
|
|
1338
|
-
: `:${sp.name}:${depTaskWithArgs[0]}`
|
|
1353
|
+
: `:${sp.name.replace(/\//, ":")}:${depTaskWithArgs[0]}`
|
|
1339
1354
|
];
|
|
1340
1355
|
gradleDepArgs = gradleDepArgs
|
|
1341
1356
|
.concat(depTaskWithArgs.slice(1))
|
|
1342
1357
|
.concat(defaultDepTaskArgs);
|
|
1343
|
-
// Support custom GRADLE_ARGS such as --configuration runtimeClassPath
|
|
1358
|
+
// Support custom GRADLE_ARGS such as --configuration runtimeClassPath (used for all tasks)
|
|
1344
1359
|
if (process.env.GRADLE_ARGS) {
|
|
1345
1360
|
const addArgs = process.env.GRADLE_ARGS.split(" ");
|
|
1346
1361
|
gradleDepArgs = gradleDepArgs.concat(addArgs);
|
|
1347
1362
|
}
|
|
1363
|
+
// gradle args only for the dependencies task
|
|
1364
|
+
if (process.env.GRADLE_ARGS_DEPENDENCIES) {
|
|
1365
|
+
const addArgs = process.env.GRADLE_ARGS_DEPENDENCIES.split(" ");
|
|
1366
|
+
gradleDepArgs = gradleDepArgs.concat(addArgs);
|
|
1367
|
+
}
|
|
1348
1368
|
console.log(
|
|
1349
1369
|
"Executing",
|
|
1350
1370
|
gradleCmd,
|
|
@@ -1376,7 +1396,8 @@ export const createJavaBom = async (path, options) => {
|
|
|
1376
1396
|
if (parsedList.dependenciesList && parsedList.dependenciesList) {
|
|
1377
1397
|
dependencies = mergeDependencies(
|
|
1378
1398
|
dependencies,
|
|
1379
|
-
parsedList.dependenciesList
|
|
1399
|
+
parsedList.dependenciesList,
|
|
1400
|
+
parentComponent
|
|
1380
1401
|
);
|
|
1381
1402
|
}
|
|
1382
1403
|
if (dlist && dlist.length) {
|
|
@@ -1779,9 +1800,9 @@ export const createNodejsBom = async (path, options) => {
|
|
|
1779
1800
|
parentComponent.type = "application";
|
|
1780
1801
|
ppurl = new PackageURL(
|
|
1781
1802
|
"npm",
|
|
1782
|
-
parentComponent.group,
|
|
1783
|
-
parentComponent.name,
|
|
1784
|
-
parentComponent.version,
|
|
1803
|
+
options.projectGroup || parentComponent.group,
|
|
1804
|
+
options.projectName || parentComponent.name,
|
|
1805
|
+
options.projectVersion || parentComponent.version,
|
|
1785
1806
|
null,
|
|
1786
1807
|
null
|
|
1787
1808
|
).toString();
|
|
@@ -1799,9 +1820,9 @@ export const createNodejsBom = async (path, options) => {
|
|
|
1799
1820
|
};
|
|
1800
1821
|
ppurl = new PackageURL(
|
|
1801
1822
|
"npm",
|
|
1802
|
-
parentComponent.group,
|
|
1803
|
-
parentComponent.name,
|
|
1804
|
-
parentComponent.version,
|
|
1823
|
+
options.projectGroup || parentComponent.group,
|
|
1824
|
+
options.projectName || parentComponent.name,
|
|
1825
|
+
options.projectVersion || parentComponent.version,
|
|
1805
1826
|
null,
|
|
1806
1827
|
null
|
|
1807
1828
|
).toString();
|
|
@@ -1817,7 +1838,8 @@ export const createNodejsBom = async (path, options) => {
|
|
|
1817
1838
|
if (parsedList.dependenciesList && parsedList.dependenciesList) {
|
|
1818
1839
|
dependencies = mergeDependencies(
|
|
1819
1840
|
dependencies,
|
|
1820
|
-
parsedList.dependenciesList
|
|
1841
|
+
parsedList.dependenciesList,
|
|
1842
|
+
parentComponent
|
|
1821
1843
|
);
|
|
1822
1844
|
}
|
|
1823
1845
|
}
|
|
@@ -1829,11 +1851,10 @@ export const createNodejsBom = async (path, options) => {
|
|
|
1829
1851
|
console.log(`Parsing ${f}`);
|
|
1830
1852
|
}
|
|
1831
1853
|
// Parse package-lock.json if available
|
|
1832
|
-
const parsedList = await parsePkgLock(f);
|
|
1854
|
+
const parsedList = await parsePkgLock(f, options);
|
|
1833
1855
|
const dlist = parsedList.pkgList;
|
|
1834
1856
|
const tmpParentComponent = dlist.splice(0, 1)[0] || {};
|
|
1835
1857
|
tmpParentComponent.type = "application";
|
|
1836
|
-
// Create a default parent component based on directory name
|
|
1837
1858
|
if (!Object.keys(parentComponent).length) {
|
|
1838
1859
|
parentComponent = tmpParentComponent;
|
|
1839
1860
|
} else {
|
|
@@ -1845,7 +1866,8 @@ export const createNodejsBom = async (path, options) => {
|
|
|
1845
1866
|
if (parsedList.dependenciesList && parsedList.dependenciesList) {
|
|
1846
1867
|
dependencies = mergeDependencies(
|
|
1847
1868
|
dependencies,
|
|
1848
|
-
parsedList.dependenciesList
|
|
1869
|
+
parsedList.dependenciesList,
|
|
1870
|
+
parentComponent
|
|
1849
1871
|
);
|
|
1850
1872
|
}
|
|
1851
1873
|
}
|
|
@@ -1920,9 +1942,9 @@ export const createNodejsBom = async (path, options) => {
|
|
|
1920
1942
|
tmpParentComponent.type = "application";
|
|
1921
1943
|
ppurl = new PackageURL(
|
|
1922
1944
|
"npm",
|
|
1923
|
-
tmpParentComponent.group,
|
|
1924
|
-
tmpParentComponent.name,
|
|
1925
|
-
tmpParentComponent.version,
|
|
1945
|
+
options.projectGroup || tmpParentComponent.group,
|
|
1946
|
+
options.projectName || tmpParentComponent.name,
|
|
1947
|
+
options.projectVersion || tmpParentComponent.version,
|
|
1926
1948
|
null,
|
|
1927
1949
|
null
|
|
1928
1950
|
).toString();
|
|
@@ -1939,15 +1961,15 @@ export const createNodejsBom = async (path, options) => {
|
|
|
1939
1961
|
const tmpA = dirName.split(sep);
|
|
1940
1962
|
dirName = tmpA[tmpA.length - 1];
|
|
1941
1963
|
const tmpParentComponent = {
|
|
1942
|
-
group: "",
|
|
1943
|
-
name: dirName,
|
|
1964
|
+
group: options.projectGroup || "",
|
|
1965
|
+
name: options.projectName || dirName,
|
|
1944
1966
|
type: "application"
|
|
1945
1967
|
};
|
|
1946
1968
|
ppurl = new PackageURL(
|
|
1947
1969
|
"npm",
|
|
1948
1970
|
tmpParentComponent.group,
|
|
1949
1971
|
tmpParentComponent.name,
|
|
1950
|
-
tmpParentComponent.version,
|
|
1972
|
+
options.projectVersion || tmpParentComponent.version,
|
|
1951
1973
|
null,
|
|
1952
1974
|
null
|
|
1953
1975
|
).toString();
|
|
@@ -1991,7 +2013,8 @@ export const createNodejsBom = async (path, options) => {
|
|
|
1991
2013
|
}
|
|
1992
2014
|
dependencies = mergeDependencies(
|
|
1993
2015
|
dependencies,
|
|
1994
|
-
parsedList.dependenciesList
|
|
2016
|
+
parsedList.dependenciesList,
|
|
2017
|
+
parentComponent
|
|
1995
2018
|
);
|
|
1996
2019
|
}
|
|
1997
2020
|
}
|
|
@@ -2020,6 +2043,8 @@ export const createNodejsBom = async (path, options) => {
|
|
|
2020
2043
|
if (parentSubComponents.length) {
|
|
2021
2044
|
parentComponent.components = parentSubComponents;
|
|
2022
2045
|
}
|
|
2046
|
+
// We need to set this to force our version to be used rather than the directory name based one.
|
|
2047
|
+
options.parentComponent = parentComponent;
|
|
2023
2048
|
return buildBomNSData(options, pkgList, "npm", {
|
|
2024
2049
|
allImports,
|
|
2025
2050
|
src: path,
|
|
@@ -2250,14 +2275,20 @@ export const createPythonBom = async (path, options) => {
|
|
|
2250
2275
|
pkgMap = getPipFrozenTree(path, undefined, tempDir);
|
|
2251
2276
|
}
|
|
2252
2277
|
// Get the imported modules and a dedupe list of packages
|
|
2253
|
-
const parentDependsOn =
|
|
2278
|
+
const parentDependsOn = new Set();
|
|
2254
2279
|
const retMap = await getPyModules(path, pkgList);
|
|
2255
2280
|
if (retMap.pkgList && retMap.pkgList.length) {
|
|
2256
2281
|
pkgList = pkgList.concat(retMap.pkgList);
|
|
2257
2282
|
for (const p of retMap.pkgList) {
|
|
2258
|
-
if (
|
|
2259
|
-
|
|
2283
|
+
if (
|
|
2284
|
+
!p.version ||
|
|
2285
|
+
(parentComponent &&
|
|
2286
|
+
p.name === parentComponent.name &&
|
|
2287
|
+
(p.version === parentComponent.version || p.version === "latest"))
|
|
2288
|
+
) {
|
|
2289
|
+
continue;
|
|
2260
2290
|
}
|
|
2291
|
+
parentDependsOn.add(`pkg:pypi/${p.name}@${p.version}`);
|
|
2261
2292
|
}
|
|
2262
2293
|
}
|
|
2263
2294
|
if (retMap.dependenciesList) {
|
|
@@ -2275,11 +2306,11 @@ export const createPythonBom = async (path, options) => {
|
|
|
2275
2306
|
if (
|
|
2276
2307
|
parentComponent &&
|
|
2277
2308
|
p.name === parentComponent.name &&
|
|
2278
|
-
p.version === parentComponent.version
|
|
2309
|
+
(p.version === parentComponent.version || p.version === "latest")
|
|
2279
2310
|
) {
|
|
2280
2311
|
continue;
|
|
2281
2312
|
}
|
|
2282
|
-
parentDependsOn.
|
|
2313
|
+
parentDependsOn.add(`pkg:pypi/${p.name}@${p.version}`);
|
|
2283
2314
|
}
|
|
2284
2315
|
if (pkgMap.pkgList && pkgMap.pkgList.length) {
|
|
2285
2316
|
pkgList = pkgList.concat(pkgMap.pkgList);
|
|
@@ -2291,13 +2322,22 @@ export const createPythonBom = async (path, options) => {
|
|
|
2291
2322
|
parentComponent
|
|
2292
2323
|
);
|
|
2293
2324
|
}
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2325
|
+
let parentPresent = false;
|
|
2326
|
+
for (const d of dependencies) {
|
|
2327
|
+
if (d.ref === parentComponent["bom-ref"]) {
|
|
2328
|
+
parentPresent = true;
|
|
2329
|
+
break;
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
if (!parentPresent) {
|
|
2333
|
+
const pdependencies = {
|
|
2334
|
+
ref: parentComponent["bom-ref"],
|
|
2335
|
+
dependsOn: Array.from(parentDependsOn).filter(
|
|
2336
|
+
(r) => parentComponent && r !== parentComponent["bom-ref"]
|
|
2337
|
+
)
|
|
2338
|
+
};
|
|
2339
|
+
dependencies.splice(0, 0, pdependencies);
|
|
2340
|
+
}
|
|
2301
2341
|
}
|
|
2302
2342
|
}
|
|
2303
2343
|
// Final fallback is to manually parse setup.py if we still
|
|
@@ -3158,7 +3198,8 @@ export const createSwiftBom = (path, options) => {
|
|
|
3158
3198
|
if (retData.dependenciesList) {
|
|
3159
3199
|
dependencies = mergeDependencies(
|
|
3160
3200
|
dependencies,
|
|
3161
|
-
retData.dependenciesList
|
|
3201
|
+
retData.dependenciesList,
|
|
3202
|
+
parentComponent
|
|
3162
3203
|
);
|
|
3163
3204
|
}
|
|
3164
3205
|
} else {
|
|
@@ -3434,7 +3475,8 @@ export const createContainerSpecLikeBom = async (path, options) => {
|
|
|
3434
3475
|
if (mbomData.bomJson.dependencies) {
|
|
3435
3476
|
dependencies = mergeDependencies(
|
|
3436
3477
|
dependencies,
|
|
3437
|
-
mbomData.bomJson.dependencies
|
|
3478
|
+
mbomData.bomJson.dependencies,
|
|
3479
|
+
parentComponent
|
|
3438
3480
|
);
|
|
3439
3481
|
}
|
|
3440
3482
|
if (mbomData.bomJson.services) {
|
|
@@ -3723,6 +3765,11 @@ export const mergeDependencies = (
|
|
|
3723
3765
|
newDependencies,
|
|
3724
3766
|
parentComponent = {}
|
|
3725
3767
|
) => {
|
|
3768
|
+
if (!parentComponent && DEBUG_MODE) {
|
|
3769
|
+
console.log(
|
|
3770
|
+
"Unable to determine parent component. Dependencies will be flattened."
|
|
3771
|
+
);
|
|
3772
|
+
}
|
|
3726
3773
|
const deps_map = {};
|
|
3727
3774
|
const parentRef =
|
|
3728
3775
|
parentComponent && parentComponent["bom-ref"]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyclonedx/cdxgen",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.4.0",
|
|
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>",
|
|
@@ -31,13 +31,14 @@
|
|
|
31
31
|
"type": "module",
|
|
32
32
|
"exports": "./index.js",
|
|
33
33
|
"bin": {
|
|
34
|
-
"cdxgen": "./bin/cdxgen.js"
|
|
34
|
+
"cdxgen": "./bin/cdxgen.js",
|
|
35
|
+
"cdxi": "./bin/repl.js"
|
|
35
36
|
},
|
|
36
37
|
"scripts": {
|
|
37
38
|
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --inject-globals false",
|
|
38
39
|
"watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch --inject-globals false",
|
|
39
|
-
"lint": "eslint *.js *.test.js bin
|
|
40
|
-
"pretty": "prettier --write *.js data/*.json bin
|
|
40
|
+
"lint": "eslint *.js *.test.js bin/*.js",
|
|
41
|
+
"pretty": "prettier --write *.js data/*.json bin/*.js --trailing-comma=none"
|
|
41
42
|
},
|
|
42
43
|
"engines": {
|
|
43
44
|
"node": ">=16"
|
|
@@ -50,8 +51,8 @@
|
|
|
50
51
|
"url": "https://github.com/cyclonedx/cdxgen/issues"
|
|
51
52
|
},
|
|
52
53
|
"dependencies": {
|
|
53
|
-
"@babel/parser": "^7.22.
|
|
54
|
-
"@babel/traverse": "^7.22.
|
|
54
|
+
"@babel/parser": "^7.22.10",
|
|
55
|
+
"@babel/traverse": "^7.22.10",
|
|
55
56
|
"ajv": "^8.12.0",
|
|
56
57
|
"ajv-formats": "^2.1.1",
|
|
57
58
|
"cheerio": "^1.0.0-rc.12",
|
|
@@ -75,11 +76,12 @@
|
|
|
75
76
|
"yargs": "^17.7.2"
|
|
76
77
|
},
|
|
77
78
|
"optionalDependencies": {
|
|
78
|
-
"@appthreat/atom": "^1.0.
|
|
79
|
+
"@appthreat/atom": "^1.0.1",
|
|
79
80
|
"@cyclonedx/cdxgen-plugins-bin": "^1.2.0",
|
|
80
81
|
"body-parser": "^1.20.2",
|
|
81
82
|
"compression": "^1.7.4",
|
|
82
|
-
"connect": "^3.7.0"
|
|
83
|
+
"connect": "^3.7.0",
|
|
84
|
+
"jsonata": "^2.0.3"
|
|
83
85
|
},
|
|
84
86
|
"files": [
|
|
85
87
|
"*.js",
|
|
@@ -88,7 +90,8 @@
|
|
|
88
90
|
],
|
|
89
91
|
"devDependencies": {
|
|
90
92
|
"caxa": "^3.0.1",
|
|
91
|
-
"eslint": "^8.
|
|
92
|
-
"jest": "^29.5.0"
|
|
93
|
+
"eslint": "^8.47.0",
|
|
94
|
+
"jest": "^29.5.0",
|
|
95
|
+
"prettier": "3.0.1"
|
|
93
96
|
}
|
|
94
97
|
}
|
package/piptree.js
CHANGED
|
@@ -57,12 +57,11 @@ def find_deps(idx, visited, reqs, traverse_count):
|
|
|
57
57
|
if not d:
|
|
58
58
|
continue
|
|
59
59
|
r.project_name = d.project_name if d is not None else r.project_name
|
|
60
|
-
if len(visited) > 100
|
|
60
|
+
if len(visited) > 100 or visited.get(r.project_name, 0) > 5:
|
|
61
61
|
return freqs
|
|
62
62
|
specs = sorted(r.specs, reverse=True)
|
|
63
63
|
specs_str = ",".join(["".join(sp) for sp in specs]) if specs else ""
|
|
64
64
|
dreqs = d.requires()
|
|
65
|
-
visited[r.project_name] = True
|
|
66
65
|
freqs.append(
|
|
67
66
|
{
|
|
68
67
|
"name": r.project_name,
|
|
@@ -71,6 +70,7 @@ def find_deps(idx, visited, reqs, traverse_count):
|
|
|
71
70
|
"dependencies": find_deps(idx, visited, dreqs, traverse_count + 1) if dreqs and traverse_count < 200 else [],
|
|
72
71
|
}
|
|
73
72
|
)
|
|
73
|
+
visited[r.project_name] = visited.get(r.project_name, 0) + 1
|
|
74
74
|
return freqs
|
|
75
75
|
|
|
76
76
|
|