@cyclonedx/cdxgen 9.4.0 → 9.5.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 +19 -50
- package/analyzer.js +29 -4
- package/bin/evinse.js +121 -0
- package/bin/repl.js +121 -7
- package/bin/verify.js +39 -0
- package/db.js +80 -0
- package/display.js +100 -1
- package/docker.test.js +9 -0
- package/evinser.js +827 -0
- package/evinser.test.js +35 -0
- package/index.js +85 -38
- package/package.json +10 -5
- package/utils.js +331 -144
- package/utils.test.js +65 -14
package/evinser.test.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { expect, test } from "@jest/globals";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
constructServiceName,
|
|
5
|
+
detectServicesFromUsages,
|
|
6
|
+
extractEndpoints
|
|
7
|
+
} from "./evinser.js";
|
|
8
|
+
|
|
9
|
+
import { readFileSync } from "node:fs";
|
|
10
|
+
|
|
11
|
+
test("Service detection test", () => {
|
|
12
|
+
const usageSlice = JSON.parse(
|
|
13
|
+
readFileSync("./test/data/usages.json", { encoding: "utf-8" })
|
|
14
|
+
);
|
|
15
|
+
const objectSlices = usageSlice.objectSlices;
|
|
16
|
+
for (const slice of objectSlices) {
|
|
17
|
+
const servicesMap = detectServicesFromUsages("java", slice);
|
|
18
|
+
expect(servicesMap).toBeDefined();
|
|
19
|
+
const serviceName = constructServiceName("java", slice);
|
|
20
|
+
expect(serviceName).toBeDefined();
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("extract endpoints test", () => {
|
|
25
|
+
expect(
|
|
26
|
+
extractEndpoints("java", '@GetMapping(value = { "/", "/home" })')
|
|
27
|
+
).toEqual(["/", "/home"]);
|
|
28
|
+
expect(
|
|
29
|
+
extractEndpoints(
|
|
30
|
+
"java",
|
|
31
|
+
'@PostMapping(value = "/issue", consumes = MediaType.APPLICATION_XML_VALUE)'
|
|
32
|
+
)
|
|
33
|
+
).toEqual(["/issue"]);
|
|
34
|
+
expect(extractEndpoints("java", '@GetMapping("/token")')).toEqual(["/token"]);
|
|
35
|
+
});
|
package/index.js
CHANGED
|
@@ -28,11 +28,13 @@ import {
|
|
|
28
28
|
collectJarNS,
|
|
29
29
|
includeMavenTestScope,
|
|
30
30
|
getMavenCommand,
|
|
31
|
+
collectGradleDependencies,
|
|
31
32
|
collectMvnDependencies,
|
|
32
33
|
parsePom,
|
|
33
34
|
parseMavenTree,
|
|
34
35
|
executeGradleProperties,
|
|
35
36
|
getGradleCommand,
|
|
37
|
+
convertJarNSToPackages,
|
|
36
38
|
parseGradleDep,
|
|
37
39
|
parseBazelSkyframe,
|
|
38
40
|
parseSbtLock,
|
|
@@ -130,8 +132,12 @@ let GRADLE_CACHE_DIR =
|
|
|
130
132
|
process.env.GRADLE_CACHE_DIR ||
|
|
131
133
|
join(homedir(), ".gradle", "caches", "modules-2", "files-2.1");
|
|
132
134
|
if (process.env.GRADLE_USER_HOME) {
|
|
133
|
-
GRADLE_CACHE_DIR =
|
|
134
|
-
process.env.GRADLE_USER_HOME
|
|
135
|
+
GRADLE_CACHE_DIR = join(
|
|
136
|
+
process.env.GRADLE_USER_HOME,
|
|
137
|
+
"caches",
|
|
138
|
+
"modules-2",
|
|
139
|
+
"files-2.1"
|
|
140
|
+
);
|
|
135
141
|
}
|
|
136
142
|
|
|
137
143
|
// Clojure CLI
|
|
@@ -168,20 +174,24 @@ const TIMEOUT_MS = parseInt(process.env.CDXGEN_TIMEOUT_MS) || 10 * 60 * 1000;
|
|
|
168
174
|
* @param {string} type Package type
|
|
169
175
|
* @returns component object
|
|
170
176
|
*/
|
|
171
|
-
const createDefaultParentComponent = (
|
|
177
|
+
const createDefaultParentComponent = (
|
|
178
|
+
path,
|
|
179
|
+
type = "application",
|
|
180
|
+
options = {}
|
|
181
|
+
) => {
|
|
172
182
|
// Expands any relative path such as dot
|
|
173
183
|
path = resolve(path);
|
|
174
184
|
// Create a parent component based on the directory name
|
|
175
|
-
let
|
|
185
|
+
let dirNameStr =
|
|
176
186
|
existsSync(path) && lstatSync(path).isDirectory()
|
|
177
187
|
? basename(path)
|
|
178
188
|
: dirname(path);
|
|
179
|
-
const tmpA =
|
|
180
|
-
|
|
189
|
+
const tmpA = dirNameStr.split(sep);
|
|
190
|
+
dirNameStr = tmpA[tmpA.length - 1];
|
|
181
191
|
const parentComponent = {
|
|
182
|
-
group: "",
|
|
183
|
-
name:
|
|
184
|
-
version: "latest",
|
|
192
|
+
group: options.projectGroup || "",
|
|
193
|
+
name: options.projectName || dirNameStr,
|
|
194
|
+
version: "" + options.projectVersion || "latest",
|
|
185
195
|
type: "application"
|
|
186
196
|
};
|
|
187
197
|
const ppurl = new PackageURL(
|
|
@@ -990,36 +1000,55 @@ const buildBomNSData = (options, pkgInfo, ptype, context) => {
|
|
|
990
1000
|
*/
|
|
991
1001
|
export const createJarBom = (path, options) => {
|
|
992
1002
|
let pkgList = [];
|
|
993
|
-
let jarFiles =
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
)
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1003
|
+
let jarFiles = [];
|
|
1004
|
+
let nsMapping = {};
|
|
1005
|
+
const parentComponent = createDefaultParentComponent(path, "maven", options);
|
|
1006
|
+
if (options.useGradleCache) {
|
|
1007
|
+
nsMapping = collectGradleDependencies(
|
|
1008
|
+
getGradleCommand(path, null),
|
|
1009
|
+
path,
|
|
1010
|
+
false,
|
|
1011
|
+
true
|
|
1012
|
+
);
|
|
1013
|
+
} else if (options.useMavenCache) {
|
|
1014
|
+
nsMapping = collectMvnDependencies(
|
|
1015
|
+
getMavenCommand(path, null),
|
|
1016
|
+
null,
|
|
1017
|
+
false,
|
|
1018
|
+
true
|
|
1019
|
+
);
|
|
1020
|
+
} else {
|
|
1021
|
+
jarFiles = getAllFiles(
|
|
1022
|
+
path,
|
|
1023
|
+
(options.multiProject ? "**/" : "") + "*.[jw]ar"
|
|
1024
|
+
);
|
|
1025
|
+
// Jenkins plugins
|
|
1026
|
+
const hpiFiles = getAllFiles(
|
|
1027
|
+
path,
|
|
1028
|
+
(options.multiProject ? "**/" : "") + "*.hpi"
|
|
1029
|
+
);
|
|
1030
|
+
if (hpiFiles.length) {
|
|
1031
|
+
jarFiles = jarFiles.concat(hpiFiles);
|
|
1009
1032
|
}
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1012
|
-
|
|
1033
|
+
const tempDir = mkdtempSync(join(tmpdir(), "jar-deps-"));
|
|
1034
|
+
for (const jar of jarFiles) {
|
|
1035
|
+
if (DEBUG_MODE) {
|
|
1036
|
+
console.log(`Parsing ${jar}`);
|
|
1037
|
+
}
|
|
1038
|
+
const dlist = extractJarArchive(jar, tempDir);
|
|
1039
|
+
if (dlist && dlist.length) {
|
|
1040
|
+
pkgList = pkgList.concat(dlist);
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
// Clean up
|
|
1044
|
+
if (tempDir && tempDir.startsWith(tmpdir()) && rmSync) {
|
|
1045
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
1013
1046
|
}
|
|
1014
1047
|
}
|
|
1015
|
-
|
|
1016
|
-
if (tempDir && tempDir.startsWith(tmpdir()) && rmSync) {
|
|
1017
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
1018
|
-
}
|
|
1048
|
+
pkgList = pkgList.concat(convertJarNSToPackages(nsMapping));
|
|
1019
1049
|
return buildBomNSData(options, pkgList, "maven", {
|
|
1020
1050
|
src: path,
|
|
1021
|
-
|
|
1022
|
-
nsMapping: {}
|
|
1051
|
+
parentComponent
|
|
1023
1052
|
});
|
|
1024
1053
|
};
|
|
1025
1054
|
|
|
@@ -1108,7 +1137,12 @@ export const createJavaBom = async (path, options) => {
|
|
|
1108
1137
|
console.log(
|
|
1109
1138
|
"Creating class names list based on available jars. This might take a few mins ..."
|
|
1110
1139
|
);
|
|
1111
|
-
jarNSMapping = collectMvnDependencies(
|
|
1140
|
+
jarNSMapping = collectMvnDependencies(
|
|
1141
|
+
mavenCmd,
|
|
1142
|
+
basePath,
|
|
1143
|
+
true,
|
|
1144
|
+
false
|
|
1145
|
+
);
|
|
1112
1146
|
}
|
|
1113
1147
|
console.log(
|
|
1114
1148
|
`Executing '${mavenCmd} ${mvnArgs.join(" ")}' in`,
|
|
@@ -1414,6 +1448,13 @@ export const createJavaBom = async (path, options) => {
|
|
|
1414
1448
|
}
|
|
1415
1449
|
} // for
|
|
1416
1450
|
if (pkgList.length) {
|
|
1451
|
+
if (parentComponent.components && parentComponent.components.length) {
|
|
1452
|
+
for (const subProj of parentComponent.components) {
|
|
1453
|
+
pkgList = pkgList.filter(
|
|
1454
|
+
(pkg) => pkg["bom-ref"] !== subProj["bom-ref"]
|
|
1455
|
+
);
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1417
1458
|
console.log(
|
|
1418
1459
|
"Obtained",
|
|
1419
1460
|
pkgList.length,
|
|
@@ -2066,7 +2107,7 @@ export const createPythonBom = async (path, options) => {
|
|
|
2066
2107
|
let dependencies = [];
|
|
2067
2108
|
let pkgList = [];
|
|
2068
2109
|
const tempDir = mkdtempSync(join(tmpdir(), "cdxgen-venv-"));
|
|
2069
|
-
let parentComponent = createDefaultParentComponent(path, "pypi");
|
|
2110
|
+
let parentComponent = createDefaultParentComponent(path, "pypi", options);
|
|
2070
2111
|
const pipenvMode = existsSync(join(path, "Pipfile"));
|
|
2071
2112
|
let poetryFiles = getAllFiles(
|
|
2072
2113
|
path,
|
|
@@ -3156,7 +3197,7 @@ export const createSwiftBom = (path, options) => {
|
|
|
3156
3197
|
if (pkgResolvedFiles.length) {
|
|
3157
3198
|
for (const f of pkgResolvedFiles) {
|
|
3158
3199
|
if (!parentComponent || !Object.keys(parentComponent).length) {
|
|
3159
|
-
parentComponent = createDefaultParentComponent(f, "swift");
|
|
3200
|
+
parentComponent = createDefaultParentComponent(f, "swift", options);
|
|
3160
3201
|
}
|
|
3161
3202
|
if (DEBUG_MODE) {
|
|
3162
3203
|
console.log("Parsing", f);
|
|
@@ -4744,14 +4785,20 @@ export const createBom = async (path, options) => {
|
|
|
4744
4785
|
return createJarBom(path, options);
|
|
4745
4786
|
case "gradle-index":
|
|
4746
4787
|
case "gradle-cache":
|
|
4788
|
+
options.useGradleCache = true;
|
|
4747
4789
|
return createJarBom(GRADLE_CACHE_DIR, options);
|
|
4748
4790
|
case "sbt-index":
|
|
4749
4791
|
case "sbt-cache":
|
|
4792
|
+
options.useSbtCache = true;
|
|
4750
4793
|
return createJarBom(SBT_CACHE_DIR, options);
|
|
4751
4794
|
case "maven-index":
|
|
4752
4795
|
case "maven-cache":
|
|
4753
4796
|
case "maven-repo":
|
|
4754
|
-
|
|
4797
|
+
options.useMavenCache = true;
|
|
4798
|
+
return createJarBom(
|
|
4799
|
+
process.env.MAVEN_CACHE_DIR || join(homedir(), ".m2", "repository"),
|
|
4800
|
+
options
|
|
4801
|
+
);
|
|
4755
4802
|
case "nodejs":
|
|
4756
4803
|
case "js":
|
|
4757
4804
|
case "javascript":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyclonedx/cdxgen",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.5.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>",
|
|
@@ -32,10 +32,12 @@
|
|
|
32
32
|
"exports": "./index.js",
|
|
33
33
|
"bin": {
|
|
34
34
|
"cdxgen": "./bin/cdxgen.js",
|
|
35
|
-
"cdxi": "./bin/repl.js"
|
|
35
|
+
"cdxi": "./bin/repl.js",
|
|
36
|
+
"evinse": "./bin/evinse.js",
|
|
37
|
+
"cdx-verify": "./bin/verify.js"
|
|
36
38
|
},
|
|
37
39
|
"scripts": {
|
|
38
|
-
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --inject-globals false",
|
|
40
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js --inject-globals false docker.test.js utils.test.js display.test.js",
|
|
39
41
|
"watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch --inject-globals false",
|
|
40
42
|
"lint": "eslint *.js *.test.js bin/*.js",
|
|
41
43
|
"pretty": "prettier --write *.js data/*.json bin/*.js --trailing-comma=none"
|
|
@@ -60,6 +62,7 @@
|
|
|
60
62
|
"glob": "^10.3.0",
|
|
61
63
|
"global-agent": "^3.0.0",
|
|
62
64
|
"got": "^13.0.0",
|
|
65
|
+
"iconv-lite": "^0.6.3",
|
|
63
66
|
"js-yaml": "^4.1.0",
|
|
64
67
|
"jws": "^4.0.0",
|
|
65
68
|
"node-stream-zip": "^1.15.0",
|
|
@@ -76,12 +79,14 @@
|
|
|
76
79
|
"yargs": "^17.7.2"
|
|
77
80
|
},
|
|
78
81
|
"optionalDependencies": {
|
|
79
|
-
"@appthreat/atom": "^1.0
|
|
82
|
+
"@appthreat/atom": "^1.1.0",
|
|
80
83
|
"@cyclonedx/cdxgen-plugins-bin": "^1.2.0",
|
|
81
84
|
"body-parser": "^1.20.2",
|
|
82
85
|
"compression": "^1.7.4",
|
|
83
86
|
"connect": "^3.7.0",
|
|
84
|
-
"jsonata": "^2.0.3"
|
|
87
|
+
"jsonata": "^2.0.3",
|
|
88
|
+
"sequelize": "^6.32.1",
|
|
89
|
+
"sqlite3": "^5.1.6"
|
|
85
90
|
},
|
|
86
91
|
"files": [
|
|
87
92
|
"*.js",
|