@cyclonedx/cdxgen 10.0.6 → 10.1.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 +1 -0
- package/bin/cdxgen.js +10 -2
- package/bin/repl.js +1 -1
- package/docker.js +1 -1
- package/evinser.js +3 -3
- package/index.js +51 -14
- package/package.json +1 -1
- package/server.js +1 -1
- package/utils.js +169 -29
- package/utils.test.js +35 -5
package/README.md
CHANGED
package/bin/cdxgen.js
CHANGED
|
@@ -404,7 +404,15 @@ const checkPermissions = (filePath) => {
|
|
|
404
404
|
fs.writeFileSync(jsonFile, bomNSData.bomJson);
|
|
405
405
|
jsonPayload = bomNSData.bomJson;
|
|
406
406
|
} else {
|
|
407
|
-
jsonPayload = JSON.stringify(
|
|
407
|
+
jsonPayload = JSON.stringify(
|
|
408
|
+
bomNSData.bomJson,
|
|
409
|
+
null,
|
|
410
|
+
options.deep ||
|
|
411
|
+
["os", "docker", "universal"].includes(options.projectType) ||
|
|
412
|
+
process.env.CI
|
|
413
|
+
? null
|
|
414
|
+
: 2
|
|
415
|
+
);
|
|
408
416
|
fs.writeFileSync(jsonFile, jsonPayload);
|
|
409
417
|
}
|
|
410
418
|
if (
|
|
@@ -499,7 +507,7 @@ const checkPermissions = (filePath) => {
|
|
|
499
507
|
bomJsonUnsignedObj.signature = signatureBlock;
|
|
500
508
|
fs.writeFileSync(
|
|
501
509
|
jsonFile,
|
|
502
|
-
JSON.stringify(bomJsonUnsignedObj, null,
|
|
510
|
+
JSON.stringify(bomJsonUnsignedObj, null, null)
|
|
503
511
|
);
|
|
504
512
|
if (publicKeyFile) {
|
|
505
513
|
// Verifying this signature
|
package/bin/repl.js
CHANGED
|
@@ -284,7 +284,7 @@ cdxgenRepl.defineCommand("save", {
|
|
|
284
284
|
if (!saveToFile) {
|
|
285
285
|
saveToFile = "bom.json";
|
|
286
286
|
}
|
|
287
|
-
fs.writeFileSync(saveToFile, JSON.stringify(sbom, null,
|
|
287
|
+
fs.writeFileSync(saveToFile, JSON.stringify(sbom, null, null));
|
|
288
288
|
console.log(`BOM saved successfully to ${saveToFile}`);
|
|
289
289
|
} else {
|
|
290
290
|
console.log(
|
package/docker.js
CHANGED
|
@@ -1194,7 +1194,7 @@ export const getCredsFromHelper = (exeSuffix, serverAddress) => {
|
|
|
1194
1194
|
export const addSkippedSrcFiles = (skippedImageSrcs, components) => {
|
|
1195
1195
|
for (const skippedImage of skippedImageSrcs) {
|
|
1196
1196
|
for (const co of components) {
|
|
1197
|
-
|
|
1197
|
+
const srcFileValues = [];
|
|
1198
1198
|
let srcImageValue;
|
|
1199
1199
|
co.properties.forEach(function (property) {
|
|
1200
1200
|
if (property.name === "oci:SrcImage") {
|
package/evinser.js
CHANGED
|
@@ -132,7 +132,7 @@ export const catalogMavenDeps = async (
|
|
|
132
132
|
namespaces: jarNSMapping[purl].namespaces
|
|
133
133
|
},
|
|
134
134
|
null,
|
|
135
|
-
|
|
135
|
+
null
|
|
136
136
|
)
|
|
137
137
|
}
|
|
138
138
|
});
|
|
@@ -165,7 +165,7 @@ export const catalogGradleDeps = async (dirPath, purlsJars, Namespaces) => {
|
|
|
165
165
|
namespaces: jarNSMapping[purl].namespaces
|
|
166
166
|
},
|
|
167
167
|
null,
|
|
168
|
-
|
|
168
|
+
null
|
|
169
169
|
)
|
|
170
170
|
}
|
|
171
171
|
});
|
|
@@ -1066,7 +1066,7 @@ export const createEvinseFile = (sliceArtefacts, options) => {
|
|
|
1066
1066
|
// Set the current timestamp to indicate this is newer
|
|
1067
1067
|
bomJson.metadata.timestamp = new Date().toISOString();
|
|
1068
1068
|
delete bomJson.signature;
|
|
1069
|
-
fs.writeFileSync(evinseOutFile, JSON.stringify(bomJson, null,
|
|
1069
|
+
fs.writeFileSync(evinseOutFile, JSON.stringify(bomJson, null, null));
|
|
1070
1070
|
if (occEvidencePresent || csEvidencePresent || servicesPresent) {
|
|
1071
1071
|
console.log(evinseOutFile, "created successfully.");
|
|
1072
1072
|
} else {
|
package/index.js
CHANGED
|
@@ -1452,7 +1452,10 @@ export const createJavaBom = async (path, options) => {
|
|
|
1452
1452
|
}
|
|
1453
1453
|
// Should we attempt to resolve class names
|
|
1454
1454
|
if (options.resolveClass || options.deep) {
|
|
1455
|
-
|
|
1455
|
+
const tmpjarNSMapping = await collectJarNS(GRADLE_CACHE_DIR);
|
|
1456
|
+
if (tmpjarNSMapping && Object.keys(tmpjarNSMapping).length) {
|
|
1457
|
+
jarNSMapping = { ...jarNSMapping, ...tmpjarNSMapping };
|
|
1458
|
+
}
|
|
1456
1459
|
}
|
|
1457
1460
|
pkgList = await getMvnMetadata(pkgList, jarNSMapping);
|
|
1458
1461
|
return buildBomNSData(options, pkgList, "maven", {
|
|
@@ -1749,7 +1752,10 @@ export const createJavaBom = async (path, options) => {
|
|
|
1749
1752
|
}
|
|
1750
1753
|
// Should we attempt to resolve class names
|
|
1751
1754
|
if (options.resolveClass || options.deep) {
|
|
1752
|
-
|
|
1755
|
+
const tmpjarNSMapping = await collectJarNS(SBT_CACHE_DIR);
|
|
1756
|
+
if (tmpjarNSMapping && Object.keys(tmpjarNSMapping).length) {
|
|
1757
|
+
jarNSMapping = { ...jarNSMapping, ...tmpjarNSMapping };
|
|
1758
|
+
}
|
|
1753
1759
|
}
|
|
1754
1760
|
pkgList = await getMvnMetadata(pkgList, jarNSMapping);
|
|
1755
1761
|
return buildBomNSData(options, pkgList, "maven", {
|
|
@@ -4145,10 +4151,13 @@ export const createRubyBom = async (path, options) => {
|
|
|
4145
4151
|
);
|
|
4146
4152
|
let gemLockFiles = getAllFiles(
|
|
4147
4153
|
path,
|
|
4148
|
-
(options.multiProject ? "**/" : "") + "Gemfile
|
|
4154
|
+
(options.multiProject ? "**/" : "") + "Gemfile*.lock",
|
|
4149
4155
|
options
|
|
4150
4156
|
);
|
|
4151
4157
|
let pkgList = [];
|
|
4158
|
+
let dependencies = [];
|
|
4159
|
+
let rootList = [];
|
|
4160
|
+
const parentComponent = createDefaultParentComponent(path, "gem", options);
|
|
4152
4161
|
const gemFileMode = gemFiles.length;
|
|
4153
4162
|
const gemLockMode = gemLockFiles.length;
|
|
4154
4163
|
if (gemFileMode && !gemLockMode && options.installDeps) {
|
|
@@ -4170,7 +4179,7 @@ export const createRubyBom = async (path, options) => {
|
|
|
4170
4179
|
}
|
|
4171
4180
|
gemLockFiles = getAllFiles(
|
|
4172
4181
|
path,
|
|
4173
|
-
(options.multiProject ? "**/" : "") + "Gemfile
|
|
4182
|
+
(options.multiProject ? "**/" : "") + "Gemfile*.lock",
|
|
4174
4183
|
options
|
|
4175
4184
|
);
|
|
4176
4185
|
if (gemLockFiles.length) {
|
|
@@ -4179,17 +4188,41 @@ export const createRubyBom = async (path, options) => {
|
|
|
4179
4188
|
console.log(`Parsing ${f}`);
|
|
4180
4189
|
}
|
|
4181
4190
|
const gemLockData = readFileSync(f, { encoding: "utf-8" });
|
|
4182
|
-
const
|
|
4183
|
-
if (
|
|
4184
|
-
pkgList = pkgList.concat(
|
|
4191
|
+
const retMap = await parseGemfileLockData(gemLockData, f);
|
|
4192
|
+
if (retMap.pkgList && retMap.pkgList.length) {
|
|
4193
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
4194
|
+
pkgList = trimComponents(pkgList);
|
|
4195
|
+
}
|
|
4196
|
+
if (retMap.dependenciesList && retMap.dependenciesList.length) {
|
|
4197
|
+
dependencies = mergeDependencies(
|
|
4198
|
+
dependencies,
|
|
4199
|
+
retMap.dependenciesList,
|
|
4200
|
+
parentComponent
|
|
4201
|
+
);
|
|
4202
|
+
}
|
|
4203
|
+
if (retMap.rootList && retMap.rootList.length) {
|
|
4204
|
+
rootList = rootList.concat(retMap.rootList);
|
|
4185
4205
|
}
|
|
4186
4206
|
}
|
|
4187
|
-
return buildBomNSData(options, pkgList, "gem", {
|
|
4188
|
-
src: path,
|
|
4189
|
-
filename: gemLockFiles.join(", ")
|
|
4190
|
-
});
|
|
4191
4207
|
}
|
|
4192
|
-
|
|
4208
|
+
if (rootList.length) {
|
|
4209
|
+
dependencies = mergeDependencies(
|
|
4210
|
+
dependencies,
|
|
4211
|
+
[
|
|
4212
|
+
{
|
|
4213
|
+
ref: parentComponent["bom-ref"],
|
|
4214
|
+
dependsOn: rootList
|
|
4215
|
+
}
|
|
4216
|
+
],
|
|
4217
|
+
parentComponent
|
|
4218
|
+
);
|
|
4219
|
+
}
|
|
4220
|
+
return buildBomNSData(options, pkgList, "gem", {
|
|
4221
|
+
src: path,
|
|
4222
|
+
dependencies,
|
|
4223
|
+
parentComponent,
|
|
4224
|
+
filename: gemLockFiles.join(", ")
|
|
4225
|
+
});
|
|
4193
4226
|
};
|
|
4194
4227
|
|
|
4195
4228
|
/**
|
|
@@ -4674,7 +4707,11 @@ export const createMultiXBom = async (pathList, options) => {
|
|
|
4674
4707
|
);
|
|
4675
4708
|
}
|
|
4676
4709
|
components = components.concat(bomData.bomJson.components);
|
|
4677
|
-
dependencies =
|
|
4710
|
+
dependencies = mergeDependencies(
|
|
4711
|
+
dependencies,
|
|
4712
|
+
bomData.bomJson.dependencies,
|
|
4713
|
+
bomData.parentComponent
|
|
4714
|
+
);
|
|
4678
4715
|
if (
|
|
4679
4716
|
bomData.parentComponent &&
|
|
4680
4717
|
Object.keys(bomData.parentComponent).length
|
|
@@ -5039,7 +5076,7 @@ export const createXBom = async (path, options) => {
|
|
|
5039
5076
|
);
|
|
5040
5077
|
const gemLockFiles = getAllFiles(
|
|
5041
5078
|
path,
|
|
5042
|
-
(options.multiProject ? "**/" : "") + "Gemfile
|
|
5079
|
+
(options.multiProject ? "**/" : "") + "Gemfile*.lock",
|
|
5043
5080
|
options
|
|
5044
5081
|
);
|
|
5045
5082
|
if (gemFiles.length || gemLockFiles.length) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyclonedx/cdxgen",
|
|
3
|
-
"version": "10.0
|
|
3
|
+
"version": "10.1.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>",
|
package/server.js
CHANGED
|
@@ -152,7 +152,7 @@ const start = (options) => {
|
|
|
152
152
|
) {
|
|
153
153
|
res.write(bomNSData.bomJson);
|
|
154
154
|
} else {
|
|
155
|
-
res.write(JSON.stringify(bomNSData.bomJson, null,
|
|
155
|
+
res.write(JSON.stringify(bomNSData.bomJson, null, null));
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
if (reqOptions.serverUrl && reqOptions.apiKey) {
|
package/utils.js
CHANGED
|
@@ -544,7 +544,7 @@ export const parsePkgJson = async (pkgJsonFile, simple = false) => {
|
|
|
544
544
|
const pkgData = JSON.parse(readFileSync(pkgJsonFile, "utf8"));
|
|
545
545
|
const pkgIdentifier = parsePackageJsonName(pkgData.name);
|
|
546
546
|
const name = pkgIdentifier.fullName || pkgData.name;
|
|
547
|
-
if (!name && !pkgJsonFile.includes("node_modules")) {
|
|
547
|
+
if (DEBUG_MODE && !name && !pkgJsonFile.includes("node_modules")) {
|
|
548
548
|
console.log(
|
|
549
549
|
`${pkgJsonFile} doesn't contain the package name. Consider using the 'npm init' command to create a valid package.json file for this project.`
|
|
550
550
|
);
|
|
@@ -4034,16 +4034,28 @@ export const parseGoVersionData = async function (buildInfoData) {
|
|
|
4034
4034
|
* @param {*} pkgList List of packages with metadata
|
|
4035
4035
|
*/
|
|
4036
4036
|
export const getRubyGemsMetadata = async function (pkgList) {
|
|
4037
|
-
const
|
|
4037
|
+
const RUBYGEMS_V2_URL =
|
|
4038
|
+
process.env.RUBYGEMS_V2_URL || "https://rubygems.org/api/v2/rubygems/";
|
|
4039
|
+
const RUBYGEMS_V1_URL =
|
|
4040
|
+
process.env.RUBYGEMS_V1_URL || "https://rubygems.org/api/v1/gems/";
|
|
4038
4041
|
const rdepList = [];
|
|
4042
|
+
const apiOptions = {
|
|
4043
|
+
responseType: "json"
|
|
4044
|
+
};
|
|
4045
|
+
if (process.env.GEM_HOST_API_KEY) {
|
|
4046
|
+
apiOptions.headers = {
|
|
4047
|
+
Authorization: process.env.GEM_HOST_API_KEY
|
|
4048
|
+
};
|
|
4049
|
+
}
|
|
4039
4050
|
for (const p of pkgList) {
|
|
4040
4051
|
try {
|
|
4041
4052
|
if (DEBUG_MODE) {
|
|
4042
4053
|
console.log(`Querying rubygems.org for ${p.name}`);
|
|
4043
4054
|
}
|
|
4044
|
-
const
|
|
4045
|
-
|
|
4046
|
-
|
|
4055
|
+
const fullUrl = p.version
|
|
4056
|
+
? `${RUBYGEMS_V2_URL}${p.name}/versions/${p.version}.json`
|
|
4057
|
+
: `${RUBYGEMS_V1_URL}${p.name}.json`;
|
|
4058
|
+
const res = await cdxgenAgent.get(fullUrl, apiOptions);
|
|
4047
4059
|
let body = res.body;
|
|
4048
4060
|
if (body && body.length) {
|
|
4049
4061
|
body = body[0];
|
|
@@ -4055,14 +4067,54 @@ export const getRubyGemsMetadata = async function (pkgList) {
|
|
|
4055
4067
|
if (body.metadata) {
|
|
4056
4068
|
if (body.metadata.source_code_uri) {
|
|
4057
4069
|
p.repository = { url: body.metadata.source_code_uri };
|
|
4070
|
+
if (
|
|
4071
|
+
body.homepage_uri &&
|
|
4072
|
+
body.homepage_uri !== body.metadata.source_code_uri
|
|
4073
|
+
) {
|
|
4074
|
+
p.homepage = { url: body.homepage_uri };
|
|
4075
|
+
}
|
|
4058
4076
|
}
|
|
4059
4077
|
if (body.metadata.bug_tracker_uri) {
|
|
4060
|
-
p.
|
|
4078
|
+
p.bugs = { url: body.metadata.bug_tracker_uri };
|
|
4061
4079
|
}
|
|
4062
4080
|
}
|
|
4063
4081
|
if (body.sha) {
|
|
4064
4082
|
p._integrity = "sha256-" + body.sha;
|
|
4065
4083
|
}
|
|
4084
|
+
if (body.authors) {
|
|
4085
|
+
p.author = body.authors;
|
|
4086
|
+
}
|
|
4087
|
+
// Track the platform such as java
|
|
4088
|
+
if (body.platform && body.platform !== "ruby") {
|
|
4089
|
+
p.properties.push({
|
|
4090
|
+
name: "cdx:gem:platform",
|
|
4091
|
+
value: body.platform
|
|
4092
|
+
});
|
|
4093
|
+
}
|
|
4094
|
+
if (body.ruby_version) {
|
|
4095
|
+
p.properties.push({
|
|
4096
|
+
name: "cdx:gem:rubyVersionSpecifiers",
|
|
4097
|
+
value: body.ruby_version
|
|
4098
|
+
});
|
|
4099
|
+
}
|
|
4100
|
+
if (body.gem_uri) {
|
|
4101
|
+
p.properties.push({
|
|
4102
|
+
name: "cdx:gem:gemUri",
|
|
4103
|
+
value: body.gem_uri
|
|
4104
|
+
});
|
|
4105
|
+
}
|
|
4106
|
+
if (body.yanked) {
|
|
4107
|
+
p.properties.push({
|
|
4108
|
+
name: "cdx:gem:yanked",
|
|
4109
|
+
value: "" + body.yanked
|
|
4110
|
+
});
|
|
4111
|
+
}
|
|
4112
|
+
if (body.prerelease) {
|
|
4113
|
+
p.properties.push({
|
|
4114
|
+
name: "cdx:gem:prerelease",
|
|
4115
|
+
value: "" + body.prerelease
|
|
4116
|
+
});
|
|
4117
|
+
}
|
|
4066
4118
|
// Use the latest version if none specified
|
|
4067
4119
|
if (!p.version) {
|
|
4068
4120
|
p.version = body.number;
|
|
@@ -4119,15 +4171,22 @@ export const parseGemspecData = async function (gemspecData) {
|
|
|
4119
4171
|
/**
|
|
4120
4172
|
* Method to parse Gemfile.lock
|
|
4121
4173
|
*
|
|
4122
|
-
* @param {
|
|
4174
|
+
* @param {object} gemLockData Gemfile.lock data
|
|
4175
|
+
* @param {string} lockFile Lock file
|
|
4123
4176
|
*/
|
|
4124
|
-
export const parseGemfileLockData = async
|
|
4125
|
-
|
|
4177
|
+
export const parseGemfileLockData = async (gemLockData, lockFile) => {
|
|
4178
|
+
let pkgList = [];
|
|
4126
4179
|
const pkgnames = {};
|
|
4180
|
+
const dependenciesList = [];
|
|
4181
|
+
const dependenciesMap = {};
|
|
4182
|
+
const pkgVersionMap = {};
|
|
4183
|
+
const rootList = [];
|
|
4127
4184
|
if (!gemLockData) {
|
|
4128
4185
|
return pkgList;
|
|
4129
4186
|
}
|
|
4130
4187
|
let specsFound = false;
|
|
4188
|
+
// We need two passes to identify components and resolve dependencies
|
|
4189
|
+
// In the first pass, we capture package name and version
|
|
4131
4190
|
gemLockData.split("\n").forEach((l) => {
|
|
4132
4191
|
l = l.trim();
|
|
4133
4192
|
l = l.replace("\r", "");
|
|
@@ -4138,35 +4197,106 @@ export const parseGemfileLockData = async function (gemLockData) {
|
|
|
4138
4197
|
if (name === "remote:") {
|
|
4139
4198
|
return;
|
|
4140
4199
|
}
|
|
4200
|
+
let version = tmpA[1];
|
|
4201
|
+
// We only allow bracket characters ()
|
|
4202
|
+
if (version.search(/[,><~ ]/) < 0) {
|
|
4203
|
+
version = version.replace(/[=()]/g, "");
|
|
4204
|
+
pkgVersionMap[name] = version;
|
|
4205
|
+
}
|
|
4206
|
+
}
|
|
4207
|
+
}
|
|
4208
|
+
if (l === "specs:") {
|
|
4209
|
+
specsFound = true;
|
|
4210
|
+
}
|
|
4211
|
+
if (l === l.toUpperCase()) {
|
|
4212
|
+
specsFound = false;
|
|
4213
|
+
}
|
|
4214
|
+
});
|
|
4215
|
+
specsFound = false;
|
|
4216
|
+
let lastParent = undefined;
|
|
4217
|
+
// In the second pass, we use the space in the prefix to figure out the dependency tree
|
|
4218
|
+
gemLockData.split("\n").forEach((l) => {
|
|
4219
|
+
l = l.replace("\r", "");
|
|
4220
|
+
if (specsFound) {
|
|
4221
|
+
const tmpA = l.split(" (");
|
|
4222
|
+
if (tmpA && tmpA.length == 2) {
|
|
4223
|
+
const nameWithPrefix = tmpA[0];
|
|
4224
|
+
const name = tmpA[0].trim();
|
|
4225
|
+
if (name === "remote:") {
|
|
4226
|
+
return;
|
|
4227
|
+
}
|
|
4228
|
+
const level = nameWithPrefix.replace(name, "").split(" ").length % 2;
|
|
4229
|
+
const purlString = new PackageURL(
|
|
4230
|
+
"gem",
|
|
4231
|
+
"",
|
|
4232
|
+
name,
|
|
4233
|
+
pkgVersionMap[name],
|
|
4234
|
+
null,
|
|
4235
|
+
null
|
|
4236
|
+
).toString();
|
|
4237
|
+
const bomRef = decodeURIComponent(purlString);
|
|
4238
|
+
if (level === 1) {
|
|
4239
|
+
lastParent = bomRef;
|
|
4240
|
+
rootList.push(bomRef);
|
|
4241
|
+
}
|
|
4242
|
+
const apkg = {
|
|
4243
|
+
name,
|
|
4244
|
+
version: pkgVersionMap[name],
|
|
4245
|
+
purl: purlString,
|
|
4246
|
+
"bom-ref": bomRef,
|
|
4247
|
+
properties: [
|
|
4248
|
+
{
|
|
4249
|
+
name: "SrcFile",
|
|
4250
|
+
value: lockFile
|
|
4251
|
+
}
|
|
4252
|
+
],
|
|
4253
|
+
evidence: {
|
|
4254
|
+
identity: {
|
|
4255
|
+
field: "purl",
|
|
4256
|
+
confidence: 0.8,
|
|
4257
|
+
methods: [
|
|
4258
|
+
{
|
|
4259
|
+
technique: "manifest-analysis",
|
|
4260
|
+
confidence: 0.8,
|
|
4261
|
+
value: lockFile
|
|
4262
|
+
}
|
|
4263
|
+
]
|
|
4264
|
+
}
|
|
4265
|
+
}
|
|
4266
|
+
};
|
|
4267
|
+
if (lastParent && lastParent !== bomRef) {
|
|
4268
|
+
if (!dependenciesMap[lastParent]) {
|
|
4269
|
+
dependenciesMap[lastParent] = new Set();
|
|
4270
|
+
}
|
|
4271
|
+
dependenciesMap[lastParent].add(bomRef);
|
|
4272
|
+
}
|
|
4273
|
+
if (!dependenciesMap[bomRef]) {
|
|
4274
|
+
dependenciesMap[bomRef] = new Set();
|
|
4275
|
+
}
|
|
4141
4276
|
if (!pkgnames[name]) {
|
|
4142
|
-
|
|
4143
|
-
version = version.replace(/[(>=<)~ ]/g, "");
|
|
4144
|
-
pkgList.push({
|
|
4145
|
-
name,
|
|
4146
|
-
version
|
|
4147
|
-
});
|
|
4277
|
+
pkgList.push(apkg);
|
|
4148
4278
|
pkgnames[name] = true;
|
|
4149
4279
|
}
|
|
4150
4280
|
}
|
|
4151
4281
|
}
|
|
4152
|
-
if (l === "specs:") {
|
|
4282
|
+
if (l.trim() === "specs:") {
|
|
4153
4283
|
specsFound = true;
|
|
4154
4284
|
}
|
|
4155
|
-
if (
|
|
4156
|
-
l === "PLATFORMS" ||
|
|
4157
|
-
l === "DEPENDENCIES" ||
|
|
4158
|
-
l === "RUBY VERSION" ||
|
|
4159
|
-
l === "BUNDLED WITH" ||
|
|
4160
|
-
l === "PATH"
|
|
4161
|
-
) {
|
|
4285
|
+
if (l.trim() == l.trim().toUpperCase()) {
|
|
4162
4286
|
specsFound = false;
|
|
4163
4287
|
}
|
|
4164
4288
|
});
|
|
4289
|
+
for (const k of Object.keys(dependenciesMap)) {
|
|
4290
|
+
dependenciesList.push({
|
|
4291
|
+
ref: k,
|
|
4292
|
+
dependsOn: Array.from(dependenciesMap[k])
|
|
4293
|
+
});
|
|
4294
|
+
}
|
|
4165
4295
|
if (FETCH_LICENSE) {
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
return pkgList;
|
|
4296
|
+
pkgList = await getRubyGemsMetadata(pkgList);
|
|
4297
|
+
return { pkgList, dependenciesList };
|
|
4169
4298
|
}
|
|
4299
|
+
return { pkgList, dependenciesList, rootList };
|
|
4170
4300
|
};
|
|
4171
4301
|
|
|
4172
4302
|
/**
|
|
@@ -6728,7 +6858,13 @@ export const collectJarNS = async (jarPath, pomPathMap = {}) => {
|
|
|
6728
6858
|
let purl = undefined;
|
|
6729
6859
|
// In some cases, the pom name might be slightly different to the jar name
|
|
6730
6860
|
if (!existsSync(pomname)) {
|
|
6731
|
-
|
|
6861
|
+
let searchDir = dirname(jf);
|
|
6862
|
+
// in case of gradle, there would be hash directory that is different for jar vs pom
|
|
6863
|
+
// so we need to start search from a level up
|
|
6864
|
+
if (searchDir.includes(join(".gradle", "caches"))) {
|
|
6865
|
+
searchDir = join(searchDir, "..");
|
|
6866
|
+
}
|
|
6867
|
+
const pomSearch = getAllFiles(searchDir, "**/*.pom");
|
|
6732
6868
|
if (pomSearch && pomSearch.length === 1) {
|
|
6733
6869
|
pomname = pomSearch[0];
|
|
6734
6870
|
}
|
|
@@ -6805,12 +6941,16 @@ export const collectJarNS = async (jarPath, pomPathMap = {}) => {
|
|
|
6805
6941
|
tmpDirParts.pop();
|
|
6806
6942
|
// Retrieve the version
|
|
6807
6943
|
const jarVersion = tmpDirParts.pop();
|
|
6944
|
+
const pkgName = jarFileName.replace(`-${jarVersion}`, "");
|
|
6808
6945
|
// The result would form the group name
|
|
6809
|
-
|
|
6946
|
+
let jarGroupName = tmpDirParts.join(".").replace(/^\./, "");
|
|
6947
|
+
if (jarGroupName.includes(pkgName)) {
|
|
6948
|
+
jarGroupName = jarGroupName.replace("." + pkgName, "");
|
|
6949
|
+
}
|
|
6810
6950
|
const purlObj = new PackageURL(
|
|
6811
6951
|
"maven",
|
|
6812
6952
|
jarGroupName,
|
|
6813
|
-
|
|
6953
|
+
pkgName,
|
|
6814
6954
|
jarVersion,
|
|
6815
6955
|
{ type: "jar" },
|
|
6816
6956
|
null
|
package/utils.test.js
CHANGED
|
@@ -2581,14 +2581,44 @@ test("parseComposerLock", () => {
|
|
|
2581
2581
|
});
|
|
2582
2582
|
|
|
2583
2583
|
test("parseGemfileLockData", async () => {
|
|
2584
|
-
|
|
2585
|
-
readFileSync("./test/data/Gemfile.lock", { encoding: "utf-8" })
|
|
2584
|
+
let retMap = await parseGemfileLockData(
|
|
2585
|
+
readFileSync("./test/data/Gemfile.lock", { encoding: "utf-8" }),
|
|
2586
|
+
"./test/data/Gemfile.lock"
|
|
2586
2587
|
);
|
|
2587
|
-
expect(
|
|
2588
|
-
expect(
|
|
2588
|
+
expect(retMap.pkgList.length).toEqual(141);
|
|
2589
|
+
expect(retMap.dependenciesList.length).toEqual(141);
|
|
2590
|
+
expect(retMap.pkgList[0]).toEqual({
|
|
2589
2591
|
name: "actioncable",
|
|
2590
|
-
version: "6.0.0"
|
|
2592
|
+
version: "6.0.0",
|
|
2593
|
+
purl: "pkg:gem/actioncable@6.0.0",
|
|
2594
|
+
"bom-ref": "pkg:gem/actioncable@6.0.0",
|
|
2595
|
+
properties: [{ name: "SrcFile", value: "./test/data/Gemfile.lock" }],
|
|
2596
|
+
evidence: {
|
|
2597
|
+
identity: {
|
|
2598
|
+
field: "purl",
|
|
2599
|
+
confidence: 0.8,
|
|
2600
|
+
methods: [
|
|
2601
|
+
{
|
|
2602
|
+
technique: "manifest-analysis",
|
|
2603
|
+
confidence: 0.8,
|
|
2604
|
+
value: "./test/data/Gemfile.lock"
|
|
2605
|
+
}
|
|
2606
|
+
]
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2591
2609
|
});
|
|
2610
|
+
retMap = await parseGemfileLockData(
|
|
2611
|
+
readFileSync("./test/data/Gemfile1.lock", { encoding: "utf-8" }),
|
|
2612
|
+
"./test/data/Gemfile1.lock"
|
|
2613
|
+
);
|
|
2614
|
+
expect(retMap.pkgList.length).toEqual(36);
|
|
2615
|
+
expect(retMap.dependenciesList.length).toEqual(36);
|
|
2616
|
+
retMap = await parseGemfileLockData(
|
|
2617
|
+
readFileSync("./test/data/Gemfile2.lock", { encoding: "utf-8" }),
|
|
2618
|
+
"./test/data/Gemfile2.lock"
|
|
2619
|
+
);
|
|
2620
|
+
expect(retMap.pkgList.length).toEqual(90);
|
|
2621
|
+
expect(retMap.dependenciesList.length).toEqual(90);
|
|
2592
2622
|
});
|
|
2593
2623
|
|
|
2594
2624
|
test("parseGemspecData", async () => {
|