@cyclonedx/cdxgen 9.9.7 → 9.9.9
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 +2 -1
- package/binary.js +52 -2
- package/evinser.js +3 -1
- package/index.js +39 -9
- package/package.json +13 -12
- package/utils.js +257 -6
- package/utils.test.js +25 -4
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ Most SBOM tools are like barcode scanners. They can scan a few package manifest
|
|
|
27
27
|
| Go | binary, go.mod, go.sum, Gopkg.lock | Yes except binary | Yes |
|
|
28
28
|
| Ruby | Gemfile.lock, gemspec | Only for Gemfile.lock | |
|
|
29
29
|
| Rust | binary, Cargo.toml, Cargo.lock | Only for Cargo.lock | |
|
|
30
|
-
| .Net | .csproj, packages.config, project.assets.json [3], packages.lock.json, .nupkg, paket.lock
|
|
30
|
+
| .Net | .csproj, .vbproj, .fsproj, packages.config, project.assets.json [3], packages.lock.json, .nupkg, paket.lock | Only for project.assets.json, packages.lock.json, paket.lock | |
|
|
31
31
|
| Dart | pubspec.lock, pubspec.yaml | Only for pubspec.lock | |
|
|
32
32
|
| Haskell | cabal.project.freeze | Yes | |
|
|
33
33
|
| Elixir | mix.lock | Yes | |
|
|
@@ -371,6 +371,7 @@ cdxgen can retain the dependency tree under the `dependencies` attribute for a s
|
|
|
371
371
|
| GRADLE_DEPENDENCY_TASK | By default cdxgen use the task "dependencies" to collect packages. Set to override the task name. |
|
|
372
372
|
| SBT_CACHE_DIR | Specify sbt cache directory. Useful for class name resolving |
|
|
373
373
|
| FETCH_LICENSE | Set this variable to `true` or `1` to fetch license information from the registry. npm and golang |
|
|
374
|
+
| SEARCH_MAVEN_ORG | If maven metadata is missing in jar file, a search is performed on search.maven.org. Set to `false` or `0` to disable search. |
|
|
374
375
|
| USE_GOSUM | Set to `true` or `1` to generate BOMs for golang projects using go.sum as the dependency source of truth, instead of go.mod |
|
|
375
376
|
| CDXGEN_TIMEOUT_MS | Default timeout for known execution involving maven, gradle or sbt |
|
|
376
377
|
| CDXGEN_SERVER_TIMEOUT_MS | Default timeout in server mode |
|
package/binary.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import { join, dirname, basename } from "node:path";
|
|
10
10
|
import { spawnSync } from "node:child_process";
|
|
11
11
|
import { PackageURL } from "packageurl-js";
|
|
12
|
-
import { DEBUG_MODE, findLicenseId } from "./utils.js";
|
|
12
|
+
import { DEBUG_MODE, TIMEOUT_MS, findLicenseId } from "./utils.js";
|
|
13
13
|
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
15
|
|
|
@@ -24,7 +24,7 @@ const isWin = _platform() === "win32";
|
|
|
24
24
|
let platform = _platform();
|
|
25
25
|
let extn = "";
|
|
26
26
|
let pluginsBinSuffix = "";
|
|
27
|
-
if (platform
|
|
27
|
+
if (platform === "win32") {
|
|
28
28
|
platform = "windows";
|
|
29
29
|
extn = ".exe";
|
|
30
30
|
}
|
|
@@ -36,6 +36,9 @@ switch (arch) {
|
|
|
36
36
|
break;
|
|
37
37
|
case "x64":
|
|
38
38
|
arch = "amd64";
|
|
39
|
+
if (platform === "windows") {
|
|
40
|
+
pluginsBinSuffix = "-windows-amd64";
|
|
41
|
+
}
|
|
39
42
|
break;
|
|
40
43
|
case "arm64":
|
|
41
44
|
pluginsBinSuffix = "-arm64";
|
|
@@ -165,7 +168,21 @@ if (existsSync(join(CDXGEN_PLUGINS_DIR, "osquery"))) {
|
|
|
165
168
|
} else if (process.env.OSQUERY_CMD) {
|
|
166
169
|
OSQUERY_BIN = process.env.OSQUERY_CMD;
|
|
167
170
|
}
|
|
171
|
+
let DOSAI_BIN = null;
|
|
172
|
+
if (existsSync(join(CDXGEN_PLUGINS_DIR, "dosai"))) {
|
|
173
|
+
if (platform === "darwin") {
|
|
174
|
+
platform = "osx";
|
|
175
|
+
}
|
|
176
|
+
DOSAI_BIN = join(
|
|
177
|
+
CDXGEN_PLUGINS_DIR,
|
|
178
|
+
"dosai",
|
|
179
|
+
"dosai-" + platform + "-" + arch + extn
|
|
180
|
+
);
|
|
181
|
+
} else if (process.env.DOSAI_CMD) {
|
|
182
|
+
DOSAI_BIN = process.env.DOSAI_CMD;
|
|
183
|
+
}
|
|
168
184
|
|
|
185
|
+
// Keep this list updated every year
|
|
169
186
|
const OS_DISTRO_ALIAS = {
|
|
170
187
|
"ubuntu-4.10": "warty",
|
|
171
188
|
"ubuntu-5.04": "hoary",
|
|
@@ -692,3 +709,36 @@ export const executeOsQuery = (query) => {
|
|
|
692
709
|
}
|
|
693
710
|
return undefined;
|
|
694
711
|
};
|
|
712
|
+
|
|
713
|
+
/**
|
|
714
|
+
* Method to execute dosai to create slices for dotnet
|
|
715
|
+
*
|
|
716
|
+
* @param {string} src
|
|
717
|
+
* @param {string} slicesFile
|
|
718
|
+
* @returns boolean
|
|
719
|
+
*/
|
|
720
|
+
export const getDotnetSlices = (src, slicesFile) => {
|
|
721
|
+
if (!DOSAI_BIN) {
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
const args = ["methods", "--path", src, "--o", slicesFile];
|
|
725
|
+
if (DEBUG_MODE) {
|
|
726
|
+
console.log("Executing", DOSAI_BIN, args.join(" "));
|
|
727
|
+
}
|
|
728
|
+
const result = spawnSync(DOSAI_BIN, args, {
|
|
729
|
+
encoding: "utf-8",
|
|
730
|
+
timeout: TIMEOUT_MS,
|
|
731
|
+
cwd: src
|
|
732
|
+
});
|
|
733
|
+
if (result.status !== 0 || result.error) {
|
|
734
|
+
if (DEBUG_MODE && result.error) {
|
|
735
|
+
if (result.stderr) {
|
|
736
|
+
console.error(result.stdout, result.stderr);
|
|
737
|
+
} else {
|
|
738
|
+
console.log("Check if dosai plugin was installed successfully.");
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
return true;
|
|
744
|
+
};
|
package/evinser.js
CHANGED
|
@@ -244,7 +244,9 @@ export const createSlice = (
|
|
|
244
244
|
args.push(path.resolve(filePath));
|
|
245
245
|
const result = executeAtom(filePath, args);
|
|
246
246
|
if (!result || !fs.existsSync(slicesFile)) {
|
|
247
|
-
console.warn(
|
|
247
|
+
console.warn(
|
|
248
|
+
`Unable to generate ${sliceType} slice using atom. Check if this is a supported language.`
|
|
249
|
+
);
|
|
248
250
|
console.log(
|
|
249
251
|
"Set the environment variable CDXGEN_DEBUG_MODE=debug to troubleshoot."
|
|
250
252
|
);
|
package/index.js
CHANGED
|
@@ -107,7 +107,8 @@ import {
|
|
|
107
107
|
frameworksList,
|
|
108
108
|
parseContainerFile,
|
|
109
109
|
parseBitbucketPipelinesFile,
|
|
110
|
-
getPyMetadata
|
|
110
|
+
getPyMetadata,
|
|
111
|
+
addEvidenceForDotnet
|
|
111
112
|
} from "./utils.js";
|
|
112
113
|
import { spawnSync } from "node:child_process";
|
|
113
114
|
import { fileURLToPath } from "node:url";
|
|
@@ -131,7 +132,8 @@ import {
|
|
|
131
132
|
getGoBuildInfo,
|
|
132
133
|
getCargoAuditableInfo,
|
|
133
134
|
executeOsQuery,
|
|
134
|
-
getOSPackages
|
|
135
|
+
getOSPackages,
|
|
136
|
+
getDotnetSlices
|
|
135
137
|
} from "./binary.js";
|
|
136
138
|
|
|
137
139
|
const isWin = _platform() === "win32";
|
|
@@ -1083,7 +1085,7 @@ export const createJarBom = async (path, options) => {
|
|
|
1083
1085
|
if (DEBUG_MODE) {
|
|
1084
1086
|
console.log(`Parsing ${jar}`);
|
|
1085
1087
|
}
|
|
1086
|
-
const dlist = extractJarArchive(jar, tempDir);
|
|
1088
|
+
const dlist = await extractJarArchive(jar, tempDir);
|
|
1087
1089
|
if (dlist && dlist.length) {
|
|
1088
1090
|
pkgList = pkgList.concat(dlist);
|
|
1089
1091
|
}
|
|
@@ -1125,7 +1127,7 @@ export const createJavaBom = async (path, options) => {
|
|
|
1125
1127
|
}
|
|
1126
1128
|
const tempDir = mkdtempSync(join(tmpdir(), "war-deps-"));
|
|
1127
1129
|
jarNSMapping = collectJarNS(tempDir);
|
|
1128
|
-
pkgList = extractJarArchive(path, tempDir, jarNSMapping);
|
|
1130
|
+
pkgList = await extractJarArchive(path, tempDir, jarNSMapping);
|
|
1129
1131
|
if (pkgList.length) {
|
|
1130
1132
|
pkgList = await getMvnMetadata(pkgList);
|
|
1131
1133
|
}
|
|
@@ -3558,7 +3560,7 @@ export const createJenkinsBom = async (path, options) => {
|
|
|
3558
3560
|
if (DEBUG_MODE) {
|
|
3559
3561
|
console.log(`Parsing ${f}`);
|
|
3560
3562
|
}
|
|
3561
|
-
const dlist = extractJarArchive(f, tempDir);
|
|
3563
|
+
const dlist = await extractJarArchive(f, tempDir);
|
|
3562
3564
|
if (dlist && dlist.length) {
|
|
3563
3565
|
pkgList = pkgList.concat(dlist);
|
|
3564
3566
|
}
|
|
@@ -4202,11 +4204,17 @@ export const createCsharpBom = async (
|
|
|
4202
4204
|
let manifestFiles = [];
|
|
4203
4205
|
let pkgData = undefined;
|
|
4204
4206
|
let dependencies = [];
|
|
4205
|
-
|
|
4207
|
+
let csProjFiles = getAllFiles(
|
|
4206
4208
|
path,
|
|
4207
4209
|
(options.multiProject ? "**/" : "") + "*.csproj",
|
|
4208
4210
|
options
|
|
4209
4211
|
);
|
|
4212
|
+
csProjFiles = csProjFiles.concat(
|
|
4213
|
+
getAllFiles(path, (options.multiProject ? "**/" : "") + "*.vbproj", options)
|
|
4214
|
+
);
|
|
4215
|
+
csProjFiles = csProjFiles.concat(
|
|
4216
|
+
getAllFiles(path, (options.multiProject ? "**/" : "") + "*.fsproj", options)
|
|
4217
|
+
);
|
|
4210
4218
|
const pkgConfigFiles = getAllFiles(
|
|
4211
4219
|
path,
|
|
4212
4220
|
(options.multiProject ? "**/" : "") + "packages.config",
|
|
@@ -4253,7 +4261,7 @@ export const createCsharpBom = async (
|
|
|
4253
4261
|
console.log(`Parsing ${af}`);
|
|
4254
4262
|
}
|
|
4255
4263
|
pkgData = readFileSync(af, { encoding: "utf-8" });
|
|
4256
|
-
let results = await parseCsProjAssetsData(pkgData);
|
|
4264
|
+
let results = await parseCsProjAssetsData(pkgData, af);
|
|
4257
4265
|
let deps = results["dependenciesList"];
|
|
4258
4266
|
let dlist = results["pkgList"];
|
|
4259
4267
|
if (dlist && dlist.length) {
|
|
@@ -4305,7 +4313,7 @@ export const createCsharpBom = async (
|
|
|
4305
4313
|
if (csProjData.charCodeAt(0) === 0xfeff) {
|
|
4306
4314
|
csProjData = csProjData.slice(1);
|
|
4307
4315
|
}
|
|
4308
|
-
const dlist = await parseCsProjData(csProjData);
|
|
4316
|
+
const dlist = await parseCsProjData(csProjData, f);
|
|
4309
4317
|
if (dlist && dlist.length) {
|
|
4310
4318
|
pkgList = pkgList.concat(dlist);
|
|
4311
4319
|
}
|
|
@@ -4336,6 +4344,22 @@ export const createCsharpBom = async (
|
|
|
4336
4344
|
if (pkgList.length) {
|
|
4337
4345
|
dependencies = mergeDependencies(dependencies, [], parentComponent);
|
|
4338
4346
|
pkgList = trimComponents(pkgList, "json");
|
|
4347
|
+
// Perform deep analysis using dosai
|
|
4348
|
+
if (options.deep) {
|
|
4349
|
+
const slicesFile = resolve(
|
|
4350
|
+
options.depsSlicesFile || join(tmpdir(), "dosai.json")
|
|
4351
|
+
);
|
|
4352
|
+
// Create the slices file if it doesn't exist
|
|
4353
|
+
if (!existsSync(slicesFile)) {
|
|
4354
|
+
const sliceResult = getDotnetSlices(resolve(path), resolve(slicesFile));
|
|
4355
|
+
if (!sliceResult && DEBUG_MODE) {
|
|
4356
|
+
console.log(
|
|
4357
|
+
"Slicing with dosai was unsuccessful. Check the errors reported in the logs above."
|
|
4358
|
+
);
|
|
4359
|
+
}
|
|
4360
|
+
}
|
|
4361
|
+
pkgList = addEvidenceForDotnet(pkgList, slicesFile, options);
|
|
4362
|
+
}
|
|
4339
4363
|
}
|
|
4340
4364
|
if (FETCH_LICENSE) {
|
|
4341
4365
|
const retMap = await getNugetMetadata(pkgList, dependencies);
|
|
@@ -5117,11 +5141,17 @@ export const createXBom = async (path, options) => {
|
|
|
5117
5141
|
}
|
|
5118
5142
|
|
|
5119
5143
|
// .Net
|
|
5120
|
-
|
|
5144
|
+
let csProjFiles = getAllFiles(
|
|
5121
5145
|
path,
|
|
5122
5146
|
(options.multiProject ? "**/" : "") + "*.csproj",
|
|
5123
5147
|
options
|
|
5124
5148
|
);
|
|
5149
|
+
csProjFiles = csProjFiles.concat(
|
|
5150
|
+
getAllFiles(path, (options.multiProject ? "**/" : "") + "*.vbproj", options)
|
|
5151
|
+
);
|
|
5152
|
+
csProjFiles = csProjFiles.concat(
|
|
5153
|
+
getAllFiles(path, (options.multiProject ? "**/" : "") + "*.fsproj", options)
|
|
5154
|
+
);
|
|
5125
5155
|
if (csProjFiles.length) {
|
|
5126
5156
|
return await createCsharpBom(path, options);
|
|
5127
5157
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyclonedx/cdxgen",
|
|
3
|
-
"version": "9.9.
|
|
3
|
+
"version": "9.9.9",
|
|
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,17 +55,17 @@
|
|
|
55
55
|
"url": "https://github.com/cyclonedx/cdxgen/issues"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@babel/parser": "^7.23.
|
|
59
|
-
"@babel/traverse": "^7.23.
|
|
58
|
+
"@babel/parser": "^7.23.6",
|
|
59
|
+
"@babel/traverse": "^7.23.6",
|
|
60
60
|
"@npmcli/arborist": "7.2.0",
|
|
61
61
|
"ajv": "^8.12.0",
|
|
62
62
|
"ajv-formats": "^2.1.1",
|
|
63
63
|
"cheerio": "^1.0.0-rc.12",
|
|
64
64
|
"edn-data": "1.1.1",
|
|
65
|
-
"find-up": "
|
|
65
|
+
"find-up": "6.3.0",
|
|
66
66
|
"glob": "^10.3.10",
|
|
67
67
|
"global-agent": "^3.0.0",
|
|
68
|
-
"got": "
|
|
68
|
+
"got": "13.0.0",
|
|
69
69
|
"iconv-lite": "^0.6.3",
|
|
70
70
|
"js-yaml": "^4.1.0",
|
|
71
71
|
"jws": "^4.0.0",
|
|
@@ -84,14 +84,15 @@
|
|
|
84
84
|
},
|
|
85
85
|
"optionalDependencies": {
|
|
86
86
|
"@appthreat/atom": "1.7.2",
|
|
87
|
-
"@cyclonedx/cdxgen-plugins-bin": "^1.4
|
|
88
|
-
"@cyclonedx/cdxgen-plugins-bin-
|
|
89
|
-
"@cyclonedx/cdxgen-plugins-bin-
|
|
87
|
+
"@cyclonedx/cdxgen-plugins-bin": "^1.5.4",
|
|
88
|
+
"@cyclonedx/cdxgen-plugins-bin-windows-amd64": "^1.5.4",
|
|
89
|
+
"@cyclonedx/cdxgen-plugins-bin-arm64": "^1.5.4",
|
|
90
|
+
"@cyclonedx/cdxgen-plugins-bin-ppc64": "^1.5.4",
|
|
90
91
|
"body-parser": "^1.20.2",
|
|
91
92
|
"compression": "^1.7.4",
|
|
92
93
|
"connect": "^3.7.0",
|
|
93
94
|
"jsonata": "^2.0.3",
|
|
94
|
-
"sequelize": "^6.35.
|
|
95
|
+
"sequelize": "^6.35.2",
|
|
95
96
|
"sqlite3": "^5.1.6"
|
|
96
97
|
},
|
|
97
98
|
"files": [
|
|
@@ -102,10 +103,10 @@
|
|
|
102
103
|
"devDependencies": {
|
|
103
104
|
"caxa": "^3.0.1",
|
|
104
105
|
"docsify-cli": "^4.4.4",
|
|
105
|
-
"eslint": "^8.
|
|
106
|
-
"eslint-config-prettier": "^9.
|
|
106
|
+
"eslint": "^8.55.0",
|
|
107
|
+
"eslint-config-prettier": "^9.1.0",
|
|
107
108
|
"eslint-plugin-prettier": "^5.0.1",
|
|
108
109
|
"jest": "^29.7.0",
|
|
109
|
-
"prettier": "3.1.
|
|
110
|
+
"prettier": "3.1.1"
|
|
110
111
|
}
|
|
111
112
|
}
|
package/utils.js
CHANGED
|
@@ -19,8 +19,10 @@ import {
|
|
|
19
19
|
readFileSync,
|
|
20
20
|
rmSync,
|
|
21
21
|
unlinkSync,
|
|
22
|
-
writeFileSync
|
|
22
|
+
writeFileSync,
|
|
23
|
+
createReadStream
|
|
23
24
|
} from "node:fs";
|
|
25
|
+
import { createHash } from "node:crypto";
|
|
24
26
|
import got from "got";
|
|
25
27
|
import Arborist from "@npmcli/arborist";
|
|
26
28
|
import path from "node:path";
|
|
@@ -120,6 +122,19 @@ export const FETCH_LICENSE =
|
|
|
120
122
|
process.env.FETCH_LICENSE &&
|
|
121
123
|
["true", "1"].includes(process.env.FETCH_LICENSE);
|
|
122
124
|
|
|
125
|
+
// Wether search.maven.org will be used to identify jars without maven metadata; default, if unset shall be 'true'
|
|
126
|
+
export const SEARCH_MAVEN_ORG =
|
|
127
|
+
!process.env.SEARCH_MAVEN_ORG ||
|
|
128
|
+
["true", "1"].includes(process.env.SEARCH_MAVEN_ORG);
|
|
129
|
+
|
|
130
|
+
// circuit breaker for search maven.org
|
|
131
|
+
let search_maven_org_errors = 0;
|
|
132
|
+
const MAX_SEARCH_MAVEN_ORG_ERRORS = 5;
|
|
133
|
+
|
|
134
|
+
// circuit breaker for get repo license
|
|
135
|
+
let get_repo_license_errors = 0;
|
|
136
|
+
const MAX_GET_REPO_LICENSE_ERRORS = 5;
|
|
137
|
+
|
|
123
138
|
const MAX_LICENSE_ID_LENGTH = 100;
|
|
124
139
|
|
|
125
140
|
let PYTHON_CMD = "python";
|
|
@@ -3353,7 +3368,7 @@ export const toGitHubApiUrl = function (repoUrl, repoMetadata) {
|
|
|
3353
3368
|
export const getRepoLicense = async function (repoUrl, repoMetadata) {
|
|
3354
3369
|
let apiUrl = toGitHubApiUrl(repoUrl, repoMetadata);
|
|
3355
3370
|
// Perform github lookups
|
|
3356
|
-
if (apiUrl) {
|
|
3371
|
+
if (apiUrl && get_repo_license_errors < MAX_GET_REPO_LICENSE_ERRORS) {
|
|
3357
3372
|
let licenseUrl = apiUrl + "/license";
|
|
3358
3373
|
const headers = {};
|
|
3359
3374
|
if (process.env.GITHUB_TOKEN) {
|
|
@@ -3399,8 +3414,10 @@ export const getRepoLicense = async function (repoUrl, repoMetadata) {
|
|
|
3399
3414
|
"Please ensure GITHUB_TOKEN is set as environment variable. " +
|
|
3400
3415
|
"See: https://docs.github.com/en/rest/overview/rate-limits-for-the-rest-api"
|
|
3401
3416
|
);
|
|
3417
|
+
get_repo_license_errors++;
|
|
3402
3418
|
} else if (!err.message.includes("404")) {
|
|
3403
3419
|
console.log(err);
|
|
3420
|
+
get_repo_license_errors++;
|
|
3404
3421
|
}
|
|
3405
3422
|
}
|
|
3406
3423
|
}
|
|
@@ -5189,7 +5206,7 @@ export const parseCsPkgData = async function (pkgData) {
|
|
|
5189
5206
|
return pkgList;
|
|
5190
5207
|
};
|
|
5191
5208
|
|
|
5192
|
-
export const parseCsProjData = async function (csProjData) {
|
|
5209
|
+
export const parseCsProjData = async function (csProjData, projFile) {
|
|
5193
5210
|
const pkgList = [];
|
|
5194
5211
|
if (!csProjData) {
|
|
5195
5212
|
return pkgList;
|
|
@@ -5218,6 +5235,27 @@ export const parseCsProjData = async function (csProjData) {
|
|
|
5218
5235
|
}
|
|
5219
5236
|
pkg.name = pref.Include;
|
|
5220
5237
|
pkg.version = pref.Version;
|
|
5238
|
+
if (projFile) {
|
|
5239
|
+
pkg.properties = [
|
|
5240
|
+
{
|
|
5241
|
+
name: "SrcFile",
|
|
5242
|
+
value: projFile
|
|
5243
|
+
}
|
|
5244
|
+
];
|
|
5245
|
+
pkg.evidence = {
|
|
5246
|
+
identity: {
|
|
5247
|
+
field: "purl",
|
|
5248
|
+
confidence: 0.7,
|
|
5249
|
+
methods: [
|
|
5250
|
+
{
|
|
5251
|
+
technique: "manifest-analysis",
|
|
5252
|
+
confidence: 0.7,
|
|
5253
|
+
value: projFile
|
|
5254
|
+
}
|
|
5255
|
+
]
|
|
5256
|
+
}
|
|
5257
|
+
};
|
|
5258
|
+
}
|
|
5221
5259
|
pkgList.push(pkg);
|
|
5222
5260
|
}
|
|
5223
5261
|
// .net framework use Reference
|
|
@@ -5232,6 +5270,27 @@ export const parseCsProjData = async function (csProjData) {
|
|
|
5232
5270
|
if (incParts.length > 1 && incParts[1].includes("Version")) {
|
|
5233
5271
|
pkg.version = incParts[1].replace("Version=", "").trim();
|
|
5234
5272
|
}
|
|
5273
|
+
if (projFile) {
|
|
5274
|
+
pkg.properties = [
|
|
5275
|
+
{
|
|
5276
|
+
name: "SrcFile",
|
|
5277
|
+
value: projFile
|
|
5278
|
+
}
|
|
5279
|
+
];
|
|
5280
|
+
pkg.evidence = {
|
|
5281
|
+
identity: {
|
|
5282
|
+
field: "purl",
|
|
5283
|
+
confidence: 0.7,
|
|
5284
|
+
methods: [
|
|
5285
|
+
{
|
|
5286
|
+
technique: "manifest-analysis",
|
|
5287
|
+
confidence: 0.7,
|
|
5288
|
+
value: projFile
|
|
5289
|
+
}
|
|
5290
|
+
]
|
|
5291
|
+
}
|
|
5292
|
+
};
|
|
5293
|
+
}
|
|
5235
5294
|
pkgList.push(pkg);
|
|
5236
5295
|
}
|
|
5237
5296
|
}
|
|
@@ -5239,7 +5298,10 @@ export const parseCsProjData = async function (csProjData) {
|
|
|
5239
5298
|
return pkgList;
|
|
5240
5299
|
};
|
|
5241
5300
|
|
|
5242
|
-
export const parseCsProjAssetsData = async function (
|
|
5301
|
+
export const parseCsProjAssetsData = async function (
|
|
5302
|
+
csProjData,
|
|
5303
|
+
assetsJsonFile
|
|
5304
|
+
) {
|
|
5243
5305
|
// extract name, operator, version from .NET package representation
|
|
5244
5306
|
// like "NLog >= 4.5.0"
|
|
5245
5307
|
function extractNameOperatorVersion(inputStr) {
|
|
@@ -5356,6 +5418,43 @@ export const parseCsProjAssetsData = async function (csProjData) {
|
|
|
5356
5418
|
} else if (lib[rootDep].sha256) {
|
|
5357
5419
|
pkg["_integrity"] = "sha256-" + lib[rootDep].sha256;
|
|
5358
5420
|
}
|
|
5421
|
+
if (lib[rootDep].files && Array.isArray(lib[rootDep].files)) {
|
|
5422
|
+
const dllFiles = new Set();
|
|
5423
|
+
lib[rootDep].files.forEach((f) => {
|
|
5424
|
+
if (
|
|
5425
|
+
f.endsWith(".dll") ||
|
|
5426
|
+
f.endsWith(".exe") ||
|
|
5427
|
+
f.endsWith(".so")
|
|
5428
|
+
) {
|
|
5429
|
+
dllFiles.add(basename(f));
|
|
5430
|
+
}
|
|
5431
|
+
});
|
|
5432
|
+
pkg.properties = [
|
|
5433
|
+
{
|
|
5434
|
+
name: "SrcFile",
|
|
5435
|
+
value: assetsJsonFile
|
|
5436
|
+
},
|
|
5437
|
+
{
|
|
5438
|
+
name: "PackageFiles",
|
|
5439
|
+
value: Array.from(dllFiles).join(", ")
|
|
5440
|
+
}
|
|
5441
|
+
];
|
|
5442
|
+
}
|
|
5443
|
+
}
|
|
5444
|
+
if (assetsJsonFile) {
|
|
5445
|
+
pkg.evidence = {
|
|
5446
|
+
identity: {
|
|
5447
|
+
field: "purl",
|
|
5448
|
+
confidence: 1,
|
|
5449
|
+
methods: [
|
|
5450
|
+
{
|
|
5451
|
+
technique: "manifest-analysis",
|
|
5452
|
+
confidence: 1,
|
|
5453
|
+
value: assetsJsonFile
|
|
5454
|
+
}
|
|
5455
|
+
]
|
|
5456
|
+
}
|
|
5457
|
+
};
|
|
5359
5458
|
}
|
|
5360
5459
|
pkgList.push(pkg);
|
|
5361
5460
|
pkgNameVersionMap[name + framework] = version;
|
|
@@ -6693,6 +6792,22 @@ export const getPomPropertiesFromMavenDir = function (mavenDir) {
|
|
|
6693
6792
|
return pomProperties;
|
|
6694
6793
|
};
|
|
6695
6794
|
|
|
6795
|
+
/**
|
|
6796
|
+
*
|
|
6797
|
+
* @param {string} hashName name of hash algorithm
|
|
6798
|
+
* @param {string} path path to file
|
|
6799
|
+
* @returns {Promise<String>} hex value of hash
|
|
6800
|
+
*/
|
|
6801
|
+
async function checksumFile(hashName, path) {
|
|
6802
|
+
return new Promise((resolve, reject) => {
|
|
6803
|
+
const hash = createHash(hashName);
|
|
6804
|
+
const stream = createReadStream(path);
|
|
6805
|
+
stream.on("error", (err) => reject(err));
|
|
6806
|
+
stream.on("data", (chunk) => hash.update(chunk));
|
|
6807
|
+
stream.on("end", () => resolve(hash.digest("hex")));
|
|
6808
|
+
});
|
|
6809
|
+
}
|
|
6810
|
+
|
|
6696
6811
|
/**
|
|
6697
6812
|
* Method to extract a war or ear file
|
|
6698
6813
|
*
|
|
@@ -6702,7 +6817,7 @@ export const getPomPropertiesFromMavenDir = function (mavenDir) {
|
|
|
6702
6817
|
*
|
|
6703
6818
|
* @return pkgList Package list
|
|
6704
6819
|
*/
|
|
6705
|
-
export const extractJarArchive = function (
|
|
6820
|
+
export const extractJarArchive = async function (
|
|
6706
6821
|
jarFile,
|
|
6707
6822
|
tempDir,
|
|
6708
6823
|
jarNSMapping = {}
|
|
@@ -6800,6 +6915,35 @@ export const extractJarArchive = function (
|
|
|
6800
6915
|
version = pomProperties["version"],
|
|
6801
6916
|
confidence = 1,
|
|
6802
6917
|
technique = "manifest-analysis";
|
|
6918
|
+
if (
|
|
6919
|
+
(!group || !name || !version) &&
|
|
6920
|
+
SEARCH_MAVEN_ORG &&
|
|
6921
|
+
search_maven_org_errors < MAX_SEARCH_MAVEN_ORG_ERRORS
|
|
6922
|
+
) {
|
|
6923
|
+
try {
|
|
6924
|
+
const sha = await checksumFile("sha1", jf);
|
|
6925
|
+
const searchurl =
|
|
6926
|
+
"https://search.maven.org/solrsearch/select?q=1:%22" +
|
|
6927
|
+
sha +
|
|
6928
|
+
"%22&rows=20&wt=json";
|
|
6929
|
+
const res = await cdxgenAgent.get(searchurl, {
|
|
6930
|
+
responseType: "json"
|
|
6931
|
+
});
|
|
6932
|
+
const data = res && res.body ? res.body["response"] : undefined;
|
|
6933
|
+
if (data && data["numFound"] == 1) {
|
|
6934
|
+
const jarInfo = data["docs"][0];
|
|
6935
|
+
group = jarInfo["g"];
|
|
6936
|
+
name = jarInfo["a"];
|
|
6937
|
+
version = jarInfo["v"];
|
|
6938
|
+
technique = "hash-comparison";
|
|
6939
|
+
}
|
|
6940
|
+
} catch (err) {
|
|
6941
|
+
if (err && err.message && !err.message.includes("404")) {
|
|
6942
|
+
console.log(err);
|
|
6943
|
+
search_maven_org_errors++;
|
|
6944
|
+
}
|
|
6945
|
+
}
|
|
6946
|
+
}
|
|
6803
6947
|
if ((!group || !name || !version) && existsSync(manifestFile)) {
|
|
6804
6948
|
confidence = 0.8;
|
|
6805
6949
|
const jarMetadata = parseJarManifest(
|
|
@@ -7208,6 +7352,7 @@ export const executeAtom = (src, args) => {
|
|
|
7208
7352
|
let cwd =
|
|
7209
7353
|
existsSync(src) && lstatSync(src).isDirectory() ? src : dirname(src);
|
|
7210
7354
|
let ATOM_BIN = getAtomCommand();
|
|
7355
|
+
let isSupported = true;
|
|
7211
7356
|
if (ATOM_BIN.includes(" ")) {
|
|
7212
7357
|
const tmpA = ATOM_BIN.split(" ");
|
|
7213
7358
|
if (tmpA && tmpA.length > 1) {
|
|
@@ -7260,6 +7405,12 @@ export const executeAtom = (src, args) => {
|
|
|
7260
7405
|
);
|
|
7261
7406
|
}
|
|
7262
7407
|
}
|
|
7408
|
+
if (result.stdout) {
|
|
7409
|
+
if (result.stdout.includes("No language frontend supported for language")) {
|
|
7410
|
+
console.log("This language is not yet supported by atom.");
|
|
7411
|
+
isSupported = false;
|
|
7412
|
+
}
|
|
7413
|
+
}
|
|
7263
7414
|
if (DEBUG_MODE) {
|
|
7264
7415
|
if (result.stdout) {
|
|
7265
7416
|
console.log(result.stdout);
|
|
@@ -7268,7 +7419,7 @@ export const executeAtom = (src, args) => {
|
|
|
7268
7419
|
console.log(result.stderr);
|
|
7269
7420
|
}
|
|
7270
7421
|
}
|
|
7271
|
-
return !result.error;
|
|
7422
|
+
return isSupported && !result.error;
|
|
7272
7423
|
};
|
|
7273
7424
|
|
|
7274
7425
|
/**
|
|
@@ -8736,3 +8887,103 @@ export const getNugetMetadata = async function (
|
|
|
8736
8887
|
dependencies: newDependencies
|
|
8737
8888
|
};
|
|
8738
8889
|
};
|
|
8890
|
+
|
|
8891
|
+
export const addEvidenceForDotnet = (pkgList, slicesFile) => {
|
|
8892
|
+
// We need two datastructures.
|
|
8893
|
+
// dll to purl mapping from the pkgList
|
|
8894
|
+
// purl to occurrences list using the slicesFile
|
|
8895
|
+
if (!slicesFile || !existsSync(slicesFile)) {
|
|
8896
|
+
return pkgList;
|
|
8897
|
+
}
|
|
8898
|
+
const pkgFilePurlMap = {};
|
|
8899
|
+
const purlLocationMap = {};
|
|
8900
|
+
const purlModulesMap = {};
|
|
8901
|
+
const purlMethodsMap = {};
|
|
8902
|
+
for (const apkg of pkgList) {
|
|
8903
|
+
if (apkg.properties && Array.isArray(apkg.properties)) {
|
|
8904
|
+
apkg.properties
|
|
8905
|
+
.filter((p) => p.name === "PackageFiles")
|
|
8906
|
+
.forEach((aprop) => {
|
|
8907
|
+
if (aprop.value) {
|
|
8908
|
+
const tmpA = aprop.value.split(", ");
|
|
8909
|
+
if (tmpA && tmpA.length) {
|
|
8910
|
+
tmpA.forEach((dllFile) => {
|
|
8911
|
+
pkgFilePurlMap[dllFile] = apkg.purl;
|
|
8912
|
+
});
|
|
8913
|
+
}
|
|
8914
|
+
}
|
|
8915
|
+
});
|
|
8916
|
+
}
|
|
8917
|
+
}
|
|
8918
|
+
const slicesData = JSON.parse(readFileSync(slicesFile, "utf-8"));
|
|
8919
|
+
if (slicesData && Object.keys(slicesData)) {
|
|
8920
|
+
if (slicesData.Dependencies) {
|
|
8921
|
+
for (const adep of slicesData.Dependencies) {
|
|
8922
|
+
if (
|
|
8923
|
+
adep.Module &&
|
|
8924
|
+
adep.Module.endsWith(".dll") &&
|
|
8925
|
+
pkgFilePurlMap[adep.Module]
|
|
8926
|
+
) {
|
|
8927
|
+
const modPurl = pkgFilePurlMap[adep.Module];
|
|
8928
|
+
if (!purlLocationMap[modPurl]) {
|
|
8929
|
+
purlLocationMap[modPurl] = new Set();
|
|
8930
|
+
}
|
|
8931
|
+
purlLocationMap[modPurl].add(`${adep.Path}#${adep.LineNumber}`);
|
|
8932
|
+
}
|
|
8933
|
+
}
|
|
8934
|
+
}
|
|
8935
|
+
if (slicesData.MethodCalls) {
|
|
8936
|
+
for (const amethodCall of slicesData.MethodCalls) {
|
|
8937
|
+
if (
|
|
8938
|
+
amethodCall.Module &&
|
|
8939
|
+
amethodCall.Module.endsWith(".dll") &&
|
|
8940
|
+
pkgFilePurlMap[amethodCall.Module]
|
|
8941
|
+
) {
|
|
8942
|
+
const modPurl = pkgFilePurlMap[amethodCall.Module];
|
|
8943
|
+
if (!purlLocationMap[modPurl]) {
|
|
8944
|
+
purlLocationMap[modPurl] = new Set();
|
|
8945
|
+
}
|
|
8946
|
+
if (!purlModulesMap[modPurl]) {
|
|
8947
|
+
purlModulesMap[modPurl] = new Set();
|
|
8948
|
+
}
|
|
8949
|
+
if (!purlMethodsMap[modPurl]) {
|
|
8950
|
+
purlMethodsMap[modPurl] = new Set();
|
|
8951
|
+
}
|
|
8952
|
+
purlLocationMap[modPurl].add(
|
|
8953
|
+
`${amethodCall.Path}#${amethodCall.LineNumber}`
|
|
8954
|
+
);
|
|
8955
|
+
purlModulesMap[modPurl].add(amethodCall.ClassName);
|
|
8956
|
+
purlMethodsMap[modPurl].add(amethodCall.CalledMethod);
|
|
8957
|
+
}
|
|
8958
|
+
}
|
|
8959
|
+
}
|
|
8960
|
+
}
|
|
8961
|
+
if (Object.keys(purlLocationMap).length) {
|
|
8962
|
+
for (const apkg of pkgList) {
|
|
8963
|
+
if (purlLocationMap[apkg.purl]) {
|
|
8964
|
+
const locationOccurrences = Array.from(
|
|
8965
|
+
purlLocationMap[apkg.purl]
|
|
8966
|
+
).sort();
|
|
8967
|
+
// Add the occurrences evidence
|
|
8968
|
+
apkg.evidence.occurrences = locationOccurrences.map((l) => ({
|
|
8969
|
+
location: l
|
|
8970
|
+
}));
|
|
8971
|
+
}
|
|
8972
|
+
// Add the imported modules to properties
|
|
8973
|
+
if (purlModulesMap[apkg.purl]) {
|
|
8974
|
+
apkg.properties.push({
|
|
8975
|
+
name: "ImportedModules",
|
|
8976
|
+
value: Array.from(purlModulesMap[apkg.purl]).sort().join(", ")
|
|
8977
|
+
});
|
|
8978
|
+
}
|
|
8979
|
+
// Add the called methods to properties
|
|
8980
|
+
if (purlMethodsMap[apkg.purl]) {
|
|
8981
|
+
apkg.properties.push({
|
|
8982
|
+
name: "CalledMethods",
|
|
8983
|
+
value: Array.from(purlMethodsMap[apkg.purl]).sort().join(", ")
|
|
8984
|
+
});
|
|
8985
|
+
}
|
|
8986
|
+
}
|
|
8987
|
+
}
|
|
8988
|
+
return pkgList;
|
|
8989
|
+
};
|
package/utils.test.js
CHANGED
|
@@ -1272,8 +1272,9 @@ test("parse project.assets.json", async () => {
|
|
|
1272
1272
|
dependenciesList: [],
|
|
1273
1273
|
pkgList: []
|
|
1274
1274
|
});
|
|
1275
|
-
|
|
1276
|
-
readFileSync("./test/data/project.assets.json", { encoding: "utf-8" })
|
|
1275
|
+
let dep_list = await parseCsProjAssetsData(
|
|
1276
|
+
readFileSync("./test/data/project.assets.json", { encoding: "utf-8" }),
|
|
1277
|
+
"./test/data/project.assets.json"
|
|
1277
1278
|
);
|
|
1278
1279
|
expect(dep_list["pkgList"].length).toEqual(302);
|
|
1279
1280
|
expect(dep_list["pkgList"][0]).toEqual({
|
|
@@ -1309,6 +1310,26 @@ test("parse project.assets.json", async () => {
|
|
|
1309
1310
|
],
|
|
1310
1311
|
ref: "pkg:nuget/Castle.Core.Tests@0.0.0"
|
|
1311
1312
|
});
|
|
1313
|
+
dep_list = await parseCsProjAssetsData(
|
|
1314
|
+
readFileSync("./test/data/project.assets1.json", { encoding: "utf-8" }),
|
|
1315
|
+
"./test/data/project.assets1.json"
|
|
1316
|
+
);
|
|
1317
|
+
expect(dep_list["pkgList"].length).toEqual(43);
|
|
1318
|
+
expect(dep_list["pkgList"][0]).toEqual({
|
|
1319
|
+
"bom-ref": "pkg:nuget/Podcast.Server@1.0.0",
|
|
1320
|
+
purl: "pkg:nuget/Podcast.Server@1.0.0",
|
|
1321
|
+
group: "",
|
|
1322
|
+
name: "Podcast.Server",
|
|
1323
|
+
type: "application",
|
|
1324
|
+
version: "1.0.0"
|
|
1325
|
+
});
|
|
1326
|
+
/*
|
|
1327
|
+
const pkgList = addEvidenceForDotnet(
|
|
1328
|
+
dep_list.pkgList,
|
|
1329
|
+
"./test/data/dosai-methods.json"
|
|
1330
|
+
);
|
|
1331
|
+
expect(pkgList.length).toEqual(43);
|
|
1332
|
+
*/
|
|
1312
1333
|
});
|
|
1313
1334
|
|
|
1314
1335
|
test("parse packages.lock.json", async () => {
|
|
@@ -1725,8 +1746,8 @@ test("parsePkgLock v3", async () => {
|
|
|
1725
1746
|
projectName: "cdxgen"
|
|
1726
1747
|
});
|
|
1727
1748
|
deps = parsedList.pkgList;
|
|
1728
|
-
expect(deps.length).toEqual(
|
|
1729
|
-
expect(parsedList.dependenciesList.length).toEqual(
|
|
1749
|
+
expect(deps.length).toEqual(1205);
|
|
1750
|
+
expect(parsedList.dependenciesList.length).toEqual(1205);
|
|
1730
1751
|
});
|
|
1731
1752
|
|
|
1732
1753
|
test("parseBowerJson", async () => {
|