@cyclonedx/cdxgen 9.0.1 → 9.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 +64 -25
- package/analyzer.js +1 -1
- package/bin/cdxgen.js +18 -24
- package/binary.js +7 -7
- package/data/bom-1.5.schema.json +3660 -0
- package/data/jsf-0.82.schema.json +211 -0
- package/data/pypi-pkg-aliases.json +84 -77
- package/data/spdx.schema.json +621 -0
- package/display.js +102 -0
- package/display.test.js +10 -0
- package/docker.js +12 -24
- package/docker.test.js +1 -1
- package/index.js +306 -294
- package/package.json +5 -3
- package/piptree.js +136 -0
- package/server.js +2 -2
- package/utils.js +500 -214
- package/utils.test.js +301 -35
package/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import Ajv from "ajv";
|
|
2
|
+
import addFormats from "ajv-formats";
|
|
1
3
|
import { platform as _platform, homedir, tmpdir } from "node:os";
|
|
2
|
-
import { join, dirname, sep } from "node:path";
|
|
4
|
+
import { basename, join, dirname, sep } from "node:path";
|
|
3
5
|
import { parse } from "ssri";
|
|
4
6
|
import {
|
|
7
|
+
lstatSync,
|
|
5
8
|
mkdtempSync,
|
|
6
9
|
rmSync,
|
|
7
10
|
existsSync,
|
|
@@ -50,7 +53,7 @@ import {
|
|
|
50
53
|
parseBdistMetadata,
|
|
51
54
|
readZipEntry,
|
|
52
55
|
parsePiplockData,
|
|
53
|
-
|
|
56
|
+
getPipFrozenTree,
|
|
54
57
|
parseReqFile,
|
|
55
58
|
getPyModules,
|
|
56
59
|
parseSetupPyFile,
|
|
@@ -148,7 +151,7 @@ if (process.env.SWIFT_CMD) {
|
|
|
148
151
|
}
|
|
149
152
|
|
|
150
153
|
// Construct sbt cache directory
|
|
151
|
-
|
|
154
|
+
const SBT_CACHE_DIR =
|
|
152
155
|
process.env.SBT_CACHE_DIR || join(homedir(), ".ivy2", "cache");
|
|
153
156
|
|
|
154
157
|
// Debug mode flag
|
|
@@ -167,7 +170,10 @@ const TIMEOUT_MS = parseInt(process.env.CDXGEN_TIMEOUT_MS) || 10 * 60 * 1000;
|
|
|
167
170
|
|
|
168
171
|
const createDefaultParentComponent = (path) => {
|
|
169
172
|
// Create a parent component based on the directory name
|
|
170
|
-
let dirName =
|
|
173
|
+
let dirName =
|
|
174
|
+
existsSync(path) && lstatSync(path).isDirectory()
|
|
175
|
+
? basename(path)
|
|
176
|
+
: dirname(path);
|
|
171
177
|
const tmpA = dirName.split(sep);
|
|
172
178
|
dirName = tmpA[tmpA.length - 1];
|
|
173
179
|
const parentComponent = {
|
|
@@ -206,55 +212,14 @@ const determineParentComponent = (options) => {
|
|
|
206
212
|
return parentComponent;
|
|
207
213
|
};
|
|
208
214
|
|
|
209
|
-
/**
|
|
210
|
-
* Method to create global external references
|
|
211
|
-
*
|
|
212
|
-
* @param pkg
|
|
213
|
-
* @returns {Array}
|
|
214
|
-
*/
|
|
215
|
-
function addGlobalReferences(src, filename, format = "xml") {
|
|
216
|
-
let externalReferences = [];
|
|
217
|
-
if (format === "json") {
|
|
218
|
-
externalReferences.push({
|
|
219
|
-
type: "other",
|
|
220
|
-
url: src,
|
|
221
|
-
comment: "Base path"
|
|
222
|
-
});
|
|
223
|
-
} else {
|
|
224
|
-
externalReferences.push({
|
|
225
|
-
reference: { "@type": "other", url: src, comment: "Base path" }
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
let packageFileMeta = filename;
|
|
229
|
-
if (!filename.includes(src)) {
|
|
230
|
-
packageFileMeta = join(src, filename);
|
|
231
|
-
}
|
|
232
|
-
if (format === "json") {
|
|
233
|
-
externalReferences.push({
|
|
234
|
-
type: "other",
|
|
235
|
-
url: packageFileMeta,
|
|
236
|
-
comment: "Package file"
|
|
237
|
-
});
|
|
238
|
-
} else {
|
|
239
|
-
externalReferences.push({
|
|
240
|
-
reference: {
|
|
241
|
-
"@type": "other",
|
|
242
|
-
url: packageFileMeta,
|
|
243
|
-
comment: "Package file"
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
return externalReferences;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
215
|
/**
|
|
251
216
|
* Function to create the services block
|
|
252
217
|
*/
|
|
253
218
|
function addServices(services, format = "xml") {
|
|
254
|
-
|
|
219
|
+
const serv_list = [];
|
|
255
220
|
for (const aserv of services) {
|
|
256
221
|
if (format === "xml") {
|
|
257
|
-
|
|
222
|
+
const service = {
|
|
258
223
|
"@bom-ref": aserv["bom-ref"],
|
|
259
224
|
group: aserv.group || "",
|
|
260
225
|
name: aserv.name,
|
|
@@ -276,9 +241,9 @@ function addServices(services, format = "xml") {
|
|
|
276
241
|
* Function to create the dependency block
|
|
277
242
|
*/
|
|
278
243
|
function addDependencies(dependencies) {
|
|
279
|
-
|
|
244
|
+
const deps_list = [];
|
|
280
245
|
for (const adep of dependencies) {
|
|
281
|
-
|
|
246
|
+
const dependsOnList = adep.dependsOn.map((v) => ({
|
|
282
247
|
"@ref": v
|
|
283
248
|
}));
|
|
284
249
|
const aentry = {
|
|
@@ -299,7 +264,7 @@ function addDependencies(dependencies) {
|
|
|
299
264
|
function addMetadata(parentComponent = {}, format = "xml", options = {}) {
|
|
300
265
|
// DO NOT fork this project to just change the vendor or author's name
|
|
301
266
|
// Try to contribute to this project by sending PR or filing issues
|
|
302
|
-
|
|
267
|
+
const metadata = {
|
|
303
268
|
timestamp: new Date().toISOString(),
|
|
304
269
|
tools: {
|
|
305
270
|
components: [
|
|
@@ -359,11 +324,17 @@ function addMetadata(parentComponent = {}, format = "xml", options = {}) {
|
|
|
359
324
|
if (parentComponent && parentComponent.components) {
|
|
360
325
|
firstPComp.components = parentComponent.components;
|
|
361
326
|
}
|
|
327
|
+
if (firstPComp.evidence) {
|
|
328
|
+
delete firstPComp.evidence;
|
|
329
|
+
}
|
|
362
330
|
metadata.component = firstPComp;
|
|
363
331
|
}
|
|
364
332
|
} else {
|
|
365
333
|
// As a fallback, retain the parent component
|
|
366
334
|
if (format === "json") {
|
|
335
|
+
if (parentComponent.evidence) {
|
|
336
|
+
delete parentComponent.evidence;
|
|
337
|
+
}
|
|
367
338
|
metadata.component = parentComponent;
|
|
368
339
|
}
|
|
369
340
|
}
|
|
@@ -508,7 +479,7 @@ function addMetadata(parentComponent = {}, format = "xml", options = {}) {
|
|
|
508
479
|
* @returns {Array}
|
|
509
480
|
*/
|
|
510
481
|
function addExternalReferences(opkg, format = "xml") {
|
|
511
|
-
|
|
482
|
+
const externalReferences = [];
|
|
512
483
|
let pkgList = [];
|
|
513
484
|
if (Array.isArray(opkg)) {
|
|
514
485
|
pkgList = opkg;
|
|
@@ -549,7 +520,7 @@ function addExternalReferences(opkg, format = "xml") {
|
|
|
549
520
|
} else {
|
|
550
521
|
if (pkg.homepage && pkg.homepage.url) {
|
|
551
522
|
externalReferences.push({
|
|
552
|
-
type: "website",
|
|
523
|
+
type: pkg.homepage.url.includes("git") ? "vcs" : "website",
|
|
553
524
|
url: pkg.homepage.url
|
|
554
525
|
});
|
|
555
526
|
}
|
|
@@ -575,17 +546,15 @@ function addExternalReferences(opkg, format = "xml") {
|
|
|
575
546
|
* For all modules in the specified package, creates a list of
|
|
576
547
|
* component objects from each one.
|
|
577
548
|
*/
|
|
578
|
-
|
|
579
|
-
export { _listComponents as listComponents };
|
|
580
|
-
function listComponents(
|
|
549
|
+
export function listComponents(
|
|
581
550
|
options,
|
|
582
551
|
allImports,
|
|
583
552
|
pkg,
|
|
584
553
|
ptype = "npm",
|
|
585
554
|
format = "xml"
|
|
586
555
|
) {
|
|
587
|
-
|
|
588
|
-
|
|
556
|
+
const compMap = {};
|
|
557
|
+
const isRootPkg = ptype === "npm";
|
|
589
558
|
if (Array.isArray(pkg)) {
|
|
590
559
|
pkg.forEach((p) => {
|
|
591
560
|
addComponent(options, allImports, p, ptype, compMap, false, format);
|
|
@@ -616,13 +585,13 @@ function addComponent(
|
|
|
616
585
|
return;
|
|
617
586
|
}
|
|
618
587
|
if (!isRootPkg) {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
588
|
+
const pkgIdentifier = parsePackageJsonName(pkg.name);
|
|
589
|
+
const author = pkg.author || "";
|
|
590
|
+
const publisher = pkg.publisher || "";
|
|
622
591
|
let group = pkg.group || pkgIdentifier.scope;
|
|
623
592
|
// Create empty group
|
|
624
593
|
group = group || "";
|
|
625
|
-
|
|
594
|
+
const name = pkgIdentifier.fullName || pkg.name || "";
|
|
626
595
|
// name is mandatory
|
|
627
596
|
if (!name) {
|
|
628
597
|
return;
|
|
@@ -640,13 +609,13 @@ function addComponent(
|
|
|
640
609
|
) {
|
|
641
610
|
return;
|
|
642
611
|
}
|
|
643
|
-
|
|
612
|
+
const version = pkg.version;
|
|
644
613
|
if (!version || ["dummy", "ignore"].includes(version)) {
|
|
645
614
|
return;
|
|
646
615
|
}
|
|
647
|
-
|
|
616
|
+
const licenses = pkg.licenses || getLicenses(pkg, format);
|
|
648
617
|
|
|
649
|
-
|
|
618
|
+
const purl =
|
|
650
619
|
pkg.purl ||
|
|
651
620
|
new PackageURL(
|
|
652
621
|
ptype,
|
|
@@ -680,7 +649,7 @@ function addComponent(
|
|
|
680
649
|
if (options.requiredOnly && ["optional", "excluded"].includes(compScope)) {
|
|
681
650
|
return;
|
|
682
651
|
}
|
|
683
|
-
|
|
652
|
+
const component = {
|
|
684
653
|
author,
|
|
685
654
|
publisher,
|
|
686
655
|
group,
|
|
@@ -709,8 +678,14 @@ function addComponent(
|
|
|
709
678
|
|
|
710
679
|
processHashes(pkg, component, format);
|
|
711
680
|
// Retain any component properties
|
|
712
|
-
if (format === "json"
|
|
713
|
-
|
|
681
|
+
if (format === "json") {
|
|
682
|
+
// Retain evidence
|
|
683
|
+
if (pkg.evidence && Object.keys(pkg.evidence).length) {
|
|
684
|
+
component.evidence = pkg.evidence;
|
|
685
|
+
}
|
|
686
|
+
if (pkg.properties && pkg.properties.length) {
|
|
687
|
+
component.properties = pkg.properties;
|
|
688
|
+
}
|
|
714
689
|
}
|
|
715
690
|
if (compMap[component.purl]) return; //remove cycles
|
|
716
691
|
compMap[component.purl] = component;
|
|
@@ -735,7 +710,7 @@ function determinePackageType(pkg) {
|
|
|
735
710
|
}
|
|
736
711
|
if (pkg.purl) {
|
|
737
712
|
try {
|
|
738
|
-
|
|
713
|
+
const purl = PackageURL.fromString(pkg.purl);
|
|
739
714
|
if (purl.type) {
|
|
740
715
|
if (["docker", "oci", "container"].includes(purl.type)) {
|
|
741
716
|
return "container";
|
|
@@ -801,7 +776,7 @@ function determinePackageType(pkg) {
|
|
|
801
776
|
}
|
|
802
777
|
}
|
|
803
778
|
if (Object.prototype.hasOwnProperty.call(pkg, "keywords")) {
|
|
804
|
-
for (
|
|
779
|
+
for (const keyword of pkg.keywords) {
|
|
805
780
|
if (keyword.toLowerCase() === "framework") {
|
|
806
781
|
return "framework";
|
|
807
782
|
}
|
|
@@ -832,7 +807,7 @@ function processHashes(pkg, component, format = "xml") {
|
|
|
832
807
|
});
|
|
833
808
|
}
|
|
834
809
|
} else if (pkg._integrity) {
|
|
835
|
-
|
|
810
|
+
const integrity = parse(pkg._integrity) || {};
|
|
836
811
|
// Components may have multiple hashes with various lengths. Check each one
|
|
837
812
|
// that is supported by the CycloneDX specification.
|
|
838
813
|
if (Object.prototype.hasOwnProperty.call(integrity, "sha512")) {
|
|
@@ -919,11 +894,6 @@ const buildBomXml = (
|
|
|
919
894
|
bom.ele("metadata").ele(metadata);
|
|
920
895
|
if (components && components.length) {
|
|
921
896
|
bom.ele("components").ele(components);
|
|
922
|
-
if (context && context.src && context.filename) {
|
|
923
|
-
bom
|
|
924
|
-
.ele("externalReferences")
|
|
925
|
-
.ele(addGlobalReferences(context.src, context.filename, "xml"));
|
|
926
|
-
}
|
|
927
897
|
if (context) {
|
|
928
898
|
if (context.services && context.services.length) {
|
|
929
899
|
bom.ele("services").ele(addServices(context.services, "xml"));
|
|
@@ -987,13 +957,6 @@ const buildBomNSData = (options, pkgInfo, ptype, context) => {
|
|
|
987
957
|
components: listComponents(options, allImports, pkgInfo, ptype, "json"),
|
|
988
958
|
dependencies
|
|
989
959
|
};
|
|
990
|
-
if (context && context.src && context.filename) {
|
|
991
|
-
jsonTpl.externalReferences = addGlobalReferences(
|
|
992
|
-
context.src,
|
|
993
|
-
context.filename,
|
|
994
|
-
"json"
|
|
995
|
-
);
|
|
996
|
-
}
|
|
997
960
|
bomNSData.bomXml = bomString;
|
|
998
961
|
bomNSData.bomJson = jsonTpl;
|
|
999
962
|
bomNSData.nsMapping = nsMapping;
|
|
@@ -1009,10 +972,7 @@ const buildBomNSData = (options, pkgInfo, ptype, context) => {
|
|
|
1009
972
|
* @param path to the project
|
|
1010
973
|
* @param options Parse options from the cli
|
|
1011
974
|
*/
|
|
1012
|
-
const createJarBom = (path, options) => {
|
|
1013
|
-
console.log(
|
|
1014
|
-
`About to create SBoM for all jar files under ${path}. This would take a while ...`
|
|
1015
|
-
);
|
|
975
|
+
export const createJarBom = (path, options) => {
|
|
1016
976
|
let pkgList = [];
|
|
1017
977
|
let jarFiles = getAllFiles(
|
|
1018
978
|
path,
|
|
@@ -1026,8 +986,8 @@ const createJarBom = (path, options) => {
|
|
|
1026
986
|
if (hpiFiles.length) {
|
|
1027
987
|
jarFiles = jarFiles.concat(hpiFiles);
|
|
1028
988
|
}
|
|
1029
|
-
|
|
1030
|
-
for (
|
|
989
|
+
const tempDir = mkdtempSync(join(tmpdir(), "jar-deps-"));
|
|
990
|
+
for (const jar of jarFiles) {
|
|
1031
991
|
if (DEBUG_MODE) {
|
|
1032
992
|
console.log(`Parsing ${jar}`);
|
|
1033
993
|
}
|
|
@@ -1038,7 +998,6 @@ const createJarBom = (path, options) => {
|
|
|
1038
998
|
}
|
|
1039
999
|
// Clean up
|
|
1040
1000
|
if (tempDir && tempDir.startsWith(tmpdir()) && rmSync) {
|
|
1041
|
-
console.log(`Cleaning up ${tempDir}`);
|
|
1042
1001
|
rmSync(tempDir, { recursive: true, force: true });
|
|
1043
1002
|
}
|
|
1044
1003
|
return buildBomNSData(options, pkgList, "maven", {
|
|
@@ -1054,7 +1013,7 @@ const createJarBom = (path, options) => {
|
|
|
1054
1013
|
* @param path to the project
|
|
1055
1014
|
* @param options Parse options from the cli
|
|
1056
1015
|
*/
|
|
1057
|
-
const createJavaBom = async (path, options) => {
|
|
1016
|
+
export const createJavaBom = async (path, options) => {
|
|
1058
1017
|
let jarNSMapping = {};
|
|
1059
1018
|
let pkgList = [];
|
|
1060
1019
|
let dependencies = [];
|
|
@@ -1068,7 +1027,7 @@ const createJavaBom = async (path, options) => {
|
|
|
1068
1027
|
if (DEBUG_MODE) {
|
|
1069
1028
|
console.log(`Retrieving packages from ${path}`);
|
|
1070
1029
|
}
|
|
1071
|
-
|
|
1030
|
+
const tempDir = mkdtempSync(join(tmpdir(), "war-deps-"));
|
|
1072
1031
|
pkgList = extractJarArchive(path, tempDir);
|
|
1073
1032
|
if (pkgList.length) {
|
|
1074
1033
|
pkgList = await getMvnMetadata(pkgList);
|
|
@@ -1119,7 +1078,7 @@ const createJavaBom = async (path, options) => {
|
|
|
1119
1078
|
const addArgs = process.env.MVN_ARGS.split(" ");
|
|
1120
1079
|
mvnArgs = mvnArgs.concat(addArgs);
|
|
1121
1080
|
}
|
|
1122
|
-
for (
|
|
1081
|
+
for (const f of pomFiles) {
|
|
1123
1082
|
const basePath = dirname(f);
|
|
1124
1083
|
const settingsXml = join(basePath, "settings.xml");
|
|
1125
1084
|
if (existsSync(settingsXml)) {
|
|
@@ -1127,7 +1086,7 @@ const createJavaBom = async (path, options) => {
|
|
|
1127
1086
|
`maven settings.xml found in ${basePath}. Please set the MVN_ARGS environment variable based on the full mvn build command used for this project.\nExample: MVN_ARGS='--settings ${settingsXml}'`
|
|
1128
1087
|
);
|
|
1129
1088
|
}
|
|
1130
|
-
|
|
1089
|
+
const mavenCmd = getMavenCommand(basePath, path);
|
|
1131
1090
|
// Should we attempt to resolve class names
|
|
1132
1091
|
if (options.resolveClass) {
|
|
1133
1092
|
console.log(
|
|
@@ -1150,8 +1109,8 @@ const createJavaBom = async (path, options) => {
|
|
|
1150
1109
|
const bomJsonFiles = getAllFiles(path, "**/target/*.json");
|
|
1151
1110
|
const bomGenerated = bomJsonFiles.length;
|
|
1152
1111
|
if (!bomGenerated || result.status !== 0 || result.error) {
|
|
1153
|
-
|
|
1154
|
-
|
|
1112
|
+
const tempDir = mkdtempSync(join(tmpdir(), "cdxmvn-"));
|
|
1113
|
+
const tempMvnTree = join(tempDir, "mvn-tree.txt");
|
|
1155
1114
|
let mvnTreeArgs = ["dependency:tree", "-DoutputFile=" + tempMvnTree];
|
|
1156
1115
|
if (process.env.MVN_ARGS) {
|
|
1157
1116
|
const addArgs = process.env.MVN_ARGS.split(" ");
|
|
@@ -1281,18 +1240,18 @@ const createJavaBom = async (path, options) => {
|
|
|
1281
1240
|
}
|
|
1282
1241
|
}
|
|
1283
1242
|
// gradle
|
|
1284
|
-
|
|
1243
|
+
const gradleFiles = getAllFiles(
|
|
1285
1244
|
path,
|
|
1286
1245
|
(options.multiProject ? "**/" : "") + "build.gradle*"
|
|
1287
1246
|
);
|
|
1288
|
-
|
|
1247
|
+
const allProjects = [];
|
|
1289
1248
|
const allProjectsAddedPurls = [];
|
|
1290
1249
|
const rootDependsOn = [];
|
|
1291
1250
|
// Execute gradle properties
|
|
1292
1251
|
if (gradleFiles && gradleFiles.length) {
|
|
1293
1252
|
let retMap = executeGradleProperties(path, null, null);
|
|
1294
1253
|
const allProjectsStr = retMap.projects || [];
|
|
1295
|
-
|
|
1254
|
+
const rootProject = retMap.rootProject;
|
|
1296
1255
|
if (rootProject) {
|
|
1297
1256
|
parentComponent = {
|
|
1298
1257
|
name: rootProject,
|
|
@@ -1314,11 +1273,11 @@ const createJavaBom = async (path, options) => {
|
|
|
1314
1273
|
}
|
|
1315
1274
|
// Get the sub-project properties and set the root dependencies
|
|
1316
1275
|
if (allProjectsStr && allProjectsStr.length) {
|
|
1317
|
-
for (
|
|
1276
|
+
for (const spstr of allProjectsStr) {
|
|
1318
1277
|
retMap = executeGradleProperties(path, null, spstr);
|
|
1319
|
-
|
|
1278
|
+
const rootSubProject = retMap.rootProject;
|
|
1320
1279
|
if (rootSubProject) {
|
|
1321
|
-
|
|
1280
|
+
const rspName = rootSubProject.replace(/^:/, "").replace(/:/, "/");
|
|
1322
1281
|
const rootSubProjectObj = {
|
|
1323
1282
|
name: rspName,
|
|
1324
1283
|
type: "application",
|
|
@@ -1356,9 +1315,9 @@ const createJavaBom = async (path, options) => {
|
|
|
1356
1315
|
}
|
|
1357
1316
|
}
|
|
1358
1317
|
if (gradleFiles && gradleFiles.length && options.installDeps) {
|
|
1359
|
-
|
|
1318
|
+
const gradleCmd = getGradleCommand(path, null);
|
|
1360
1319
|
allProjects.push(parentComponent);
|
|
1361
|
-
for (
|
|
1320
|
+
for (const sp of allProjects) {
|
|
1362
1321
|
let gradleDepArgs = [
|
|
1363
1322
|
sp.purl === parentComponent.purl
|
|
1364
1323
|
? "dependencies"
|
|
@@ -1452,13 +1411,13 @@ const createJavaBom = async (path, options) => {
|
|
|
1452
1411
|
|
|
1453
1412
|
// Bazel
|
|
1454
1413
|
// Look for the BUILD file only in the root directory
|
|
1455
|
-
|
|
1414
|
+
const bazelFiles = getAllFiles(path, "BUILD");
|
|
1456
1415
|
if (bazelFiles && bazelFiles.length) {
|
|
1457
1416
|
let BAZEL_CMD = "bazel";
|
|
1458
1417
|
if (process.env.BAZEL_HOME) {
|
|
1459
1418
|
BAZEL_CMD = join(process.env.BAZEL_HOME, "bin", "bazel");
|
|
1460
1419
|
}
|
|
1461
|
-
for (
|
|
1420
|
+
for (const f of bazelFiles) {
|
|
1462
1421
|
const basePath = dirname(f);
|
|
1463
1422
|
// Invoke bazel build first
|
|
1464
1423
|
const bazelTarget = process.env.BAZEL_TARGET || ":all";
|
|
@@ -1500,7 +1459,7 @@ const createJavaBom = async (path, options) => {
|
|
|
1500
1459
|
console.error(result.stdout, result.stderr);
|
|
1501
1460
|
options.failOnError && process.exit(1);
|
|
1502
1461
|
}
|
|
1503
|
-
|
|
1462
|
+
const stdout = result.stdout;
|
|
1504
1463
|
if (stdout) {
|
|
1505
1464
|
const cmdOutput = Buffer.from(stdout).toString();
|
|
1506
1465
|
const dlist = parseBazelSkyframe(cmdOutput);
|
|
@@ -1545,7 +1504,7 @@ const createJavaBom = async (path, options) => {
|
|
|
1545
1504
|
);
|
|
1546
1505
|
|
|
1547
1506
|
let sbtProjects = [];
|
|
1548
|
-
for (
|
|
1507
|
+
for (const i in sbtProjectFiles) {
|
|
1549
1508
|
// parent dir of sbtProjectFile is the `project` directory
|
|
1550
1509
|
// parent dir of `project` is the sbt root project directory
|
|
1551
1510
|
const baseDir = dirname(dirname(sbtProjectFiles[i]));
|
|
@@ -1558,7 +1517,7 @@ const createJavaBom = async (path, options) => {
|
|
|
1558
1517
|
path,
|
|
1559
1518
|
(options.multiProject ? "**/" : "") + "*.sbt"
|
|
1560
1519
|
);
|
|
1561
|
-
for (
|
|
1520
|
+
for (const i in sbtProjectFiles) {
|
|
1562
1521
|
const baseDir = dirname(sbtProjectFiles[i]);
|
|
1563
1522
|
sbtProjects = sbtProjects.concat(baseDir);
|
|
1564
1523
|
}
|
|
@@ -1566,7 +1525,7 @@ const createJavaBom = async (path, options) => {
|
|
|
1566
1525
|
|
|
1567
1526
|
sbtProjects = [...new Set(sbtProjects)]; // eliminate duplicates
|
|
1568
1527
|
|
|
1569
|
-
|
|
1528
|
+
const sbtLockFiles = getAllFiles(
|
|
1570
1529
|
path,
|
|
1571
1530
|
(options.multiProject ? "**/" : "") + "build.sbt.lock"
|
|
1572
1531
|
);
|
|
@@ -1575,15 +1534,15 @@ const createJavaBom = async (path, options) => {
|
|
|
1575
1534
|
let pkgList = [];
|
|
1576
1535
|
// If the project use sbt lock files
|
|
1577
1536
|
if (sbtLockFiles && sbtLockFiles.length) {
|
|
1578
|
-
for (
|
|
1537
|
+
for (const f of sbtLockFiles) {
|
|
1579
1538
|
const dlist = parseSbtLock(f);
|
|
1580
1539
|
if (dlist && dlist.length) {
|
|
1581
1540
|
pkgList = pkgList.concat(dlist);
|
|
1582
1541
|
}
|
|
1583
1542
|
}
|
|
1584
1543
|
} else {
|
|
1585
|
-
|
|
1586
|
-
|
|
1544
|
+
const SBT_CMD = process.env.SBT_CMD || "sbt";
|
|
1545
|
+
const sbtVersion = determineSbtVersion(path);
|
|
1587
1546
|
if (DEBUG_MODE) {
|
|
1588
1547
|
console.log("Detected sbt version: " + sbtVersion);
|
|
1589
1548
|
}
|
|
@@ -1596,11 +1555,11 @@ const createJavaBom = async (path, options) => {
|
|
|
1596
1555
|
const useSlashSyntax = gte(sbtVersion, "1.5.0");
|
|
1597
1556
|
const isDependencyTreeBuiltIn =
|
|
1598
1557
|
sbtVersion != null && gte(sbtVersion, "1.4.0");
|
|
1599
|
-
|
|
1600
|
-
|
|
1558
|
+
const tempDir = mkdtempSync(join(tmpdir(), "cdxsbt-"));
|
|
1559
|
+
const tempSbtgDir = mkdtempSync(join(tmpdir(), "cdxsbtg-"));
|
|
1601
1560
|
mkdirSync(tempSbtgDir, { recursive: true });
|
|
1602
1561
|
// Create temporary plugins file
|
|
1603
|
-
|
|
1562
|
+
const tempSbtPlugins = join(tempSbtgDir, "dep-plugins.sbt");
|
|
1604
1563
|
|
|
1605
1564
|
// Requires a custom version of `sbt-dependency-graph` that
|
|
1606
1565
|
// supports `--append` for `toFile` subtask.
|
|
@@ -1613,9 +1572,9 @@ const createJavaBom = async (path, options) => {
|
|
|
1613
1572
|
}
|
|
1614
1573
|
writeFileSync(tempSbtPlugins, sbtPluginDefinition);
|
|
1615
1574
|
|
|
1616
|
-
for (
|
|
1575
|
+
for (const i in sbtProjects) {
|
|
1617
1576
|
const basePath = sbtProjects[i];
|
|
1618
|
-
|
|
1577
|
+
const dlFile = join(tempDir, "dl-" + i + ".tmp");
|
|
1619
1578
|
console.log(
|
|
1620
1579
|
"Executing",
|
|
1621
1580
|
SBT_CMD,
|
|
@@ -1624,8 +1583,8 @@ const createJavaBom = async (path, options) => {
|
|
|
1624
1583
|
"using plugins",
|
|
1625
1584
|
tempSbtgDir
|
|
1626
1585
|
);
|
|
1627
|
-
|
|
1628
|
-
|
|
1586
|
+
let sbtArgs = [];
|
|
1587
|
+
let pluginFile = null;
|
|
1629
1588
|
if (standalonePluginFile) {
|
|
1630
1589
|
sbtArgs = [
|
|
1631
1590
|
`-addPluginSbtFile=${tempSbtPlugins}`,
|
|
@@ -1709,7 +1668,7 @@ const createJavaBom = async (path, options) => {
|
|
|
1709
1668
|
* @param path to the project
|
|
1710
1669
|
* @param options Parse options from the cli
|
|
1711
1670
|
*/
|
|
1712
|
-
const createNodejsBom = async (path, options) => {
|
|
1671
|
+
export const createNodejsBom = async (path, options) => {
|
|
1713
1672
|
let pkgList = [];
|
|
1714
1673
|
let manifestFiles = [];
|
|
1715
1674
|
let dependencies = [];
|
|
@@ -1720,7 +1679,7 @@ const createNodejsBom = async (path, options) => {
|
|
|
1720
1679
|
const pkgJsonFiles = getAllFiles(path, "**/package.json");
|
|
1721
1680
|
// Are there any package.json files in the container?
|
|
1722
1681
|
if (pkgJsonFiles.length) {
|
|
1723
|
-
for (
|
|
1682
|
+
for (const pj of pkgJsonFiles) {
|
|
1724
1683
|
const dlist = await parsePkgJson(pj);
|
|
1725
1684
|
if (dlist && dlist.length) {
|
|
1726
1685
|
pkgList = pkgList.concat(dlist);
|
|
@@ -1776,7 +1735,7 @@ const createNodejsBom = async (path, options) => {
|
|
|
1776
1735
|
// Parse min js files
|
|
1777
1736
|
if (minJsFiles && minJsFiles.length) {
|
|
1778
1737
|
manifestFiles = manifestFiles.concat(minJsFiles);
|
|
1779
|
-
for (
|
|
1738
|
+
for (const f of minJsFiles) {
|
|
1780
1739
|
const dlist = await parseMinJs(f);
|
|
1781
1740
|
if (dlist && dlist.length) {
|
|
1782
1741
|
pkgList = pkgList.concat(dlist);
|
|
@@ -1786,7 +1745,7 @@ const createNodejsBom = async (path, options) => {
|
|
|
1786
1745
|
// Parse bower json files
|
|
1787
1746
|
if (bowerFiles && bowerFiles.length) {
|
|
1788
1747
|
manifestFiles = manifestFiles.concat(bowerFiles);
|
|
1789
|
-
for (
|
|
1748
|
+
for (const f of bowerFiles) {
|
|
1790
1749
|
const dlist = await parseBowerJson(f);
|
|
1791
1750
|
if (dlist && dlist.length) {
|
|
1792
1751
|
pkgList = pkgList.concat(dlist);
|
|
@@ -1795,7 +1754,7 @@ const createNodejsBom = async (path, options) => {
|
|
|
1795
1754
|
}
|
|
1796
1755
|
if (pnpmLockFiles && pnpmLockFiles.length) {
|
|
1797
1756
|
manifestFiles = manifestFiles.concat(pnpmLockFiles);
|
|
1798
|
-
for (
|
|
1757
|
+
for (const f of pnpmLockFiles) {
|
|
1799
1758
|
const basePath = dirname(f);
|
|
1800
1759
|
// Determine the parent component
|
|
1801
1760
|
const packageJsonF = join(basePath, "package.json");
|
|
@@ -1841,7 +1800,7 @@ const createNodejsBom = async (path, options) => {
|
|
|
1841
1800
|
}
|
|
1842
1801
|
if (pkgLockFiles && pkgLockFiles.length) {
|
|
1843
1802
|
manifestFiles = manifestFiles.concat(pkgLockFiles);
|
|
1844
|
-
for (
|
|
1803
|
+
for (const f of pkgLockFiles) {
|
|
1845
1804
|
if (DEBUG_MODE) {
|
|
1846
1805
|
console.log(`Parsing ${f}`);
|
|
1847
1806
|
}
|
|
@@ -1917,7 +1876,7 @@ const createNodejsBom = async (path, options) => {
|
|
|
1917
1876
|
}
|
|
1918
1877
|
if (yarnLockFiles && yarnLockFiles.length) {
|
|
1919
1878
|
manifestFiles = manifestFiles.concat(yarnLockFiles);
|
|
1920
|
-
for (
|
|
1879
|
+
for (const f of yarnLockFiles) {
|
|
1921
1880
|
if (DEBUG_MODE) {
|
|
1922
1881
|
console.log(`Parsing ${f}`);
|
|
1923
1882
|
}
|
|
@@ -1993,7 +1952,7 @@ const createNodejsBom = async (path, options) => {
|
|
|
1993
1952
|
"**/package.json"
|
|
1994
1953
|
);
|
|
1995
1954
|
manifestFiles = manifestFiles.concat(pkgJsonFiles);
|
|
1996
|
-
for (
|
|
1955
|
+
for (const pkgjf of pkgJsonFiles) {
|
|
1997
1956
|
const dlist = await parsePkgJson(pkgjf);
|
|
1998
1957
|
if (dlist && dlist.length) {
|
|
1999
1958
|
pkgList = pkgList.concat(dlist);
|
|
@@ -2026,9 +1985,13 @@ const createNodejsBom = async (path, options) => {
|
|
|
2026
1985
|
* @param path to the project
|
|
2027
1986
|
* @param options Parse options from the cli
|
|
2028
1987
|
*/
|
|
2029
|
-
const createPythonBom = async (path, options) => {
|
|
1988
|
+
export const createPythonBom = async (path, options) => {
|
|
2030
1989
|
let allImports = {};
|
|
2031
1990
|
let metadataFilename = "";
|
|
1991
|
+
let dependencies = [];
|
|
1992
|
+
let pkgList = [];
|
|
1993
|
+
const tempDir = mkdtempSync(join(tmpdir(), "cdxgen-venv-"));
|
|
1994
|
+
const parentComponent = createDefaultParentComponent(path);
|
|
2032
1995
|
const pipenvMode = existsSync(join(path, "Pipfile"));
|
|
2033
1996
|
const poetryFiles = getAllFiles(
|
|
2034
1997
|
path,
|
|
@@ -2054,7 +2017,6 @@ const createPythonBom = async (path, options) => {
|
|
|
2054
2017
|
path,
|
|
2055
2018
|
(options.multiProject ? "**/" : "") + "*.egg-info"
|
|
2056
2019
|
);
|
|
2057
|
-
let pkgList = [];
|
|
2058
2020
|
const setupPy = join(path, "setup.py");
|
|
2059
2021
|
const pyProjectFile = join(path, "pyproject.toml");
|
|
2060
2022
|
const pyProjectMode = existsSync(pyProjectFile);
|
|
@@ -2065,7 +2027,7 @@ const createPythonBom = async (path, options) => {
|
|
|
2065
2027
|
// Poetry sets up its own virtual env containing site-packages so
|
|
2066
2028
|
// we give preference to poetry lock file. Issue# 129
|
|
2067
2029
|
if (poetryMode) {
|
|
2068
|
-
for (
|
|
2030
|
+
for (const f of poetryFiles) {
|
|
2069
2031
|
const lockData = readFileSync(f, { encoding: "utf-8" });
|
|
2070
2032
|
const dlist = await parsePoetrylockData(lockData);
|
|
2071
2033
|
if (dlist && dlist.length) {
|
|
@@ -2078,7 +2040,7 @@ const createPythonBom = async (path, options) => {
|
|
|
2078
2040
|
});
|
|
2079
2041
|
} else if (metadataFiles && metadataFiles.length) {
|
|
2080
2042
|
// dist-info directories
|
|
2081
|
-
for (
|
|
2043
|
+
for (const mf of metadataFiles) {
|
|
2082
2044
|
const mData = readFileSync(mf, {
|
|
2083
2045
|
encoding: "utf-8"
|
|
2084
2046
|
});
|
|
@@ -2090,7 +2052,7 @@ const createPythonBom = async (path, options) => {
|
|
|
2090
2052
|
}
|
|
2091
2053
|
// .whl files. Zip file containing dist-info directory
|
|
2092
2054
|
if (whlFiles && whlFiles.length) {
|
|
2093
|
-
for (
|
|
2055
|
+
for (const wf of whlFiles) {
|
|
2094
2056
|
const mData = await readZipEntry(wf, "METADATA");
|
|
2095
2057
|
if (mData) {
|
|
2096
2058
|
const dlist = parseBdistMetadata(mData);
|
|
@@ -2102,7 +2064,7 @@ const createPythonBom = async (path, options) => {
|
|
|
2102
2064
|
}
|
|
2103
2065
|
// .egg-info files
|
|
2104
2066
|
if (eggInfoFiles && eggInfoFiles.length) {
|
|
2105
|
-
for (
|
|
2067
|
+
for (const ef of eggInfoFiles) {
|
|
2106
2068
|
const dlist = parseBdistMetadata(readFileSync(ef, { encoding: "utf-8" }));
|
|
2107
2069
|
if (dlist && dlist.length) {
|
|
2108
2070
|
pkgList = pkgList.concat(dlist);
|
|
@@ -2126,15 +2088,15 @@ const createPythonBom = async (path, options) => {
|
|
|
2126
2088
|
} else if (requirementsMode) {
|
|
2127
2089
|
metadataFilename = "requirements.txt";
|
|
2128
2090
|
if (reqFiles && reqFiles.length) {
|
|
2129
|
-
for (
|
|
2091
|
+
for (const f of reqFiles) {
|
|
2130
2092
|
const basePath = dirname(f);
|
|
2131
2093
|
let reqData = undefined;
|
|
2132
2094
|
let frozen = false;
|
|
2133
2095
|
// Attempt to pip freeze in a virtualenv to improve precision
|
|
2134
2096
|
if (options.installDeps) {
|
|
2135
|
-
const
|
|
2136
|
-
if (
|
|
2137
|
-
pkgList = pkgList.concat(
|
|
2097
|
+
const pkgMap = getPipFrozenTree(basePath, f, tempDir);
|
|
2098
|
+
if (pkgMap.pkgList && pkgMap.pkgList.length) {
|
|
2099
|
+
pkgList = pkgList.concat(pkgMap.pkgList);
|
|
2138
2100
|
frozen = true;
|
|
2139
2101
|
}
|
|
2140
2102
|
}
|
|
@@ -2154,7 +2116,7 @@ const createPythonBom = async (path, options) => {
|
|
|
2154
2116
|
} // for
|
|
2155
2117
|
metadataFilename = reqFiles.join(", ");
|
|
2156
2118
|
} else if (reqDirFiles && reqDirFiles.length) {
|
|
2157
|
-
for (
|
|
2119
|
+
for (const j in reqDirFiles) {
|
|
2158
2120
|
const f = reqDirFiles[j];
|
|
2159
2121
|
const reqData = readFileSync(f, { encoding: "utf-8" });
|
|
2160
2122
|
const dlist = await parseReqFile(reqData, false);
|
|
@@ -2168,27 +2130,48 @@ const createPythonBom = async (path, options) => {
|
|
|
2168
2130
|
}
|
|
2169
2131
|
// Use atom in requirements, setup.py and pyproject.toml mode
|
|
2170
2132
|
if (requirementsMode || setupPyMode || pyProjectMode) {
|
|
2171
|
-
let dlist = undefined;
|
|
2172
2133
|
/**
|
|
2173
2134
|
* The order of preference is pyproject.toml (newer) and then setup.py
|
|
2174
2135
|
*/
|
|
2175
2136
|
if (options.installDeps) {
|
|
2137
|
+
let pkgMap = undefined;
|
|
2176
2138
|
if (pyProjectMode) {
|
|
2177
|
-
|
|
2139
|
+
pkgMap = getPipFrozenTree(path, pyProjectFile, tempDir);
|
|
2178
2140
|
} else if (setupPyMode) {
|
|
2179
|
-
|
|
2141
|
+
pkgMap = getPipFrozenTree(path, setupPy, tempDir);
|
|
2142
|
+
} else {
|
|
2143
|
+
pkgMap = getPipFrozenTree(path, undefined, tempDir);
|
|
2144
|
+
}
|
|
2145
|
+
// Get the imported modules and a dedupe list of packages
|
|
2146
|
+
const parentDependsOn = [];
|
|
2147
|
+
const retMap = await getPyModules(path, pkgList);
|
|
2148
|
+
if (retMap.pkgList && retMap.pkgList.length) {
|
|
2149
|
+
pkgList = pkgList.concat(retMap.pkgList);
|
|
2150
|
+
for (const p of retMap.pkgList) {
|
|
2151
|
+
parentDependsOn.push(`pkg:pypi/${p.name}@${p.version}`);
|
|
2152
|
+
}
|
|
2180
2153
|
}
|
|
2181
|
-
if (
|
|
2182
|
-
|
|
2154
|
+
if (retMap.dependenciesList) {
|
|
2155
|
+
dependencies = mergeDependencies(dependencies, retMap.dependenciesList);
|
|
2183
2156
|
}
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2157
|
+
if (retMap.allImports) {
|
|
2158
|
+
allImports = { ...allImports, ...retMap.allImports };
|
|
2159
|
+
}
|
|
2160
|
+
// Complete the dependency tree by making parent component depend on the first level
|
|
2161
|
+
for (const p of pkgMap.rootList) {
|
|
2162
|
+
parentDependsOn.push(`pkg:pypi/${p.name}@${p.version}`);
|
|
2163
|
+
}
|
|
2164
|
+
if (pkgMap.pkgList && pkgMap.pkgList.length) {
|
|
2165
|
+
pkgList = pkgList.concat(pkgMap.pkgList);
|
|
2166
|
+
}
|
|
2167
|
+
if (pkgMap.dependenciesList) {
|
|
2168
|
+
dependencies = mergeDependencies(dependencies, pkgMap.dependenciesList);
|
|
2169
|
+
}
|
|
2170
|
+
const pdependencies = {
|
|
2171
|
+
ref: parentComponent.purl,
|
|
2172
|
+
dependsOn: parentDependsOn
|
|
2173
|
+
};
|
|
2174
|
+
dependencies.splice(0, 0, pdependencies);
|
|
2192
2175
|
}
|
|
2193
2176
|
}
|
|
2194
2177
|
// Final fallback is to manually parse setup.py if we still
|
|
@@ -2200,10 +2183,16 @@ const createPythonBom = async (path, options) => {
|
|
|
2200
2183
|
pkgList = pkgList.concat(dlist);
|
|
2201
2184
|
}
|
|
2202
2185
|
}
|
|
2186
|
+
// Clean up
|
|
2187
|
+
if (tempDir && tempDir.startsWith(tmpdir()) && rmSync) {
|
|
2188
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
2189
|
+
}
|
|
2203
2190
|
return buildBomNSData(options, pkgList, "pypi", {
|
|
2204
2191
|
allImports,
|
|
2205
2192
|
src: path,
|
|
2206
|
-
filename: metadataFilename
|
|
2193
|
+
filename: metadataFilename,
|
|
2194
|
+
dependencies,
|
|
2195
|
+
parentComponent
|
|
2207
2196
|
});
|
|
2208
2197
|
};
|
|
2209
2198
|
|
|
@@ -2213,7 +2202,7 @@ const createPythonBom = async (path, options) => {
|
|
|
2213
2202
|
* @param path to the project
|
|
2214
2203
|
* @param options Parse options from the cli
|
|
2215
2204
|
*/
|
|
2216
|
-
const createGoBom = async (path, options) => {
|
|
2205
|
+
export const createGoBom = async (path, options) => {
|
|
2217
2206
|
let pkgList = [];
|
|
2218
2207
|
// Is this a binary file
|
|
2219
2208
|
let maybeBinary = false;
|
|
@@ -2230,8 +2219,8 @@ const createGoBom = async (path, options) => {
|
|
|
2230
2219
|
}
|
|
2231
2220
|
// Since this pkg list is derived from the binary mark them as used.
|
|
2232
2221
|
const allImports = {};
|
|
2233
|
-
for (
|
|
2234
|
-
|
|
2222
|
+
for (const mpkg of pkgList) {
|
|
2223
|
+
const pkgFullName = `${mpkg.group}/${mpkg.name}`;
|
|
2235
2224
|
allImports[pkgFullName] = true;
|
|
2236
2225
|
}
|
|
2237
2226
|
return buildBomNSData(options, pkgList, "golang", {
|
|
@@ -2255,7 +2244,7 @@ const createGoBom = async (path, options) => {
|
|
|
2255
2244
|
"Using go.sum to generate BOMs for go projects may return an inaccurate representation of transitive dependencies.\nSee: https://github.com/golang/go/wiki/Modules#is-gosum-a-lock-file-why-does-gosum-include-information-for-module-versions-i-am-no-longer-using\n",
|
|
2256
2245
|
"Set USE_GOSUM=false to generate BOMs using go.mod as the dependency source of truth."
|
|
2257
2246
|
);
|
|
2258
|
-
for (
|
|
2247
|
+
for (const f of gosumFiles) {
|
|
2259
2248
|
if (DEBUG_MODE) {
|
|
2260
2249
|
console.log(`Parsing ${f}`);
|
|
2261
2250
|
}
|
|
@@ -2274,7 +2263,7 @@ const createGoBom = async (path, options) => {
|
|
|
2274
2263
|
// If USE_GOSUM is false, generate BOM components using go.mod.
|
|
2275
2264
|
const gosumMap = {};
|
|
2276
2265
|
if (gosumFiles.length) {
|
|
2277
|
-
for (
|
|
2266
|
+
for (const f of gosumFiles) {
|
|
2278
2267
|
if (DEBUG_MODE) {
|
|
2279
2268
|
console.log(`Parsing ${f}`);
|
|
2280
2269
|
}
|
|
@@ -2303,7 +2292,7 @@ const createGoBom = async (path, options) => {
|
|
|
2303
2292
|
let shouldManuallyParse = false;
|
|
2304
2293
|
// Use the go list -deps and go mod why commands to generate a good quality BoM for non-docker invocations
|
|
2305
2294
|
if (!["docker", "oci", "os"].includes(options.projectType)) {
|
|
2306
|
-
for (
|
|
2295
|
+
for (const f of gomodFiles) {
|
|
2307
2296
|
const basePath = dirname(f);
|
|
2308
2297
|
// Ignore vendor packages
|
|
2309
2298
|
if (basePath.includes("/vendor/") || basePath.includes("/build/")) {
|
|
@@ -2349,11 +2338,11 @@ const createGoBom = async (path, options) => {
|
|
|
2349
2338
|
);
|
|
2350
2339
|
}
|
|
2351
2340
|
// Using go mod why detect required packages
|
|
2352
|
-
for (
|
|
2341
|
+
for (const apkg of pkgList) {
|
|
2353
2342
|
if (circuitBreak) {
|
|
2354
2343
|
break;
|
|
2355
2344
|
}
|
|
2356
|
-
|
|
2345
|
+
const pkgFullName = `${apkg.name}`;
|
|
2357
2346
|
if (apkg.scope === "required") {
|
|
2358
2347
|
allImports[pkgFullName] = true;
|
|
2359
2348
|
continue;
|
|
@@ -2375,7 +2364,7 @@ const createGoBom = async (path, options) => {
|
|
|
2375
2364
|
const mstdout = mresult.stdout;
|
|
2376
2365
|
if (mstdout) {
|
|
2377
2366
|
const cmdOutput = Buffer.from(mstdout).toString();
|
|
2378
|
-
|
|
2367
|
+
const whyPkg = parseGoModWhy(cmdOutput);
|
|
2379
2368
|
if (whyPkg == pkgFullName) {
|
|
2380
2369
|
allImports[pkgFullName] = true;
|
|
2381
2370
|
}
|
|
@@ -2399,7 +2388,7 @@ const createGoBom = async (path, options) => {
|
|
|
2399
2388
|
"Manually parsing go.mod files. The resultant BoM would be incomplete."
|
|
2400
2389
|
);
|
|
2401
2390
|
}
|
|
2402
|
-
for (
|
|
2391
|
+
for (const f of gomodFiles) {
|
|
2403
2392
|
if (DEBUG_MODE) {
|
|
2404
2393
|
console.log(`Parsing ${f}`);
|
|
2405
2394
|
}
|
|
@@ -2414,7 +2403,7 @@ const createGoBom = async (path, options) => {
|
|
|
2414
2403
|
filename: gomodFiles.join(", ")
|
|
2415
2404
|
});
|
|
2416
2405
|
} else if (gopkgLockFiles.length) {
|
|
2417
|
-
for (
|
|
2406
|
+
for (const f of gopkgLockFiles) {
|
|
2418
2407
|
if (DEBUG_MODE) {
|
|
2419
2408
|
console.log(`Parsing ${f}`);
|
|
2420
2409
|
}
|
|
@@ -2440,7 +2429,7 @@ const createGoBom = async (path, options) => {
|
|
|
2440
2429
|
* @param path to the project
|
|
2441
2430
|
* @param options Parse options from the cli
|
|
2442
2431
|
*/
|
|
2443
|
-
const createRustBom = async (path, options) => {
|
|
2432
|
+
export const createRustBom = async (path, options) => {
|
|
2444
2433
|
let pkgList = [];
|
|
2445
2434
|
// Is this a binary file
|
|
2446
2435
|
let maybeBinary = false;
|
|
@@ -2457,8 +2446,8 @@ const createRustBom = async (path, options) => {
|
|
|
2457
2446
|
}
|
|
2458
2447
|
// Since this pkg list is derived from the binary mark them as used.
|
|
2459
2448
|
const allImports = {};
|
|
2460
|
-
for (
|
|
2461
|
-
|
|
2449
|
+
for (const mpkg of pkgList) {
|
|
2450
|
+
const pkgFullName = `${mpkg.group}/${mpkg.name}`;
|
|
2462
2451
|
allImports[pkgFullName] = true;
|
|
2463
2452
|
}
|
|
2464
2453
|
return buildBomNSData(options, pkgList, "cargo", {
|
|
@@ -2476,9 +2465,9 @@ const createRustBom = async (path, options) => {
|
|
|
2476
2465
|
(options.multiProject ? "**/" : "") + "Cargo.toml"
|
|
2477
2466
|
);
|
|
2478
2467
|
const cargoMode = cargoFiles.length;
|
|
2479
|
-
|
|
2468
|
+
const cargoLockMode = cargoLockFiles.length;
|
|
2480
2469
|
if (cargoMode && !cargoLockMode) {
|
|
2481
|
-
for (
|
|
2470
|
+
for (const f of cargoFiles) {
|
|
2482
2471
|
if (DEBUG_MODE) {
|
|
2483
2472
|
console.log(`Parsing ${f}`);
|
|
2484
2473
|
}
|
|
@@ -2499,7 +2488,7 @@ const createRustBom = async (path, options) => {
|
|
|
2499
2488
|
(options.multiProject ? "**/" : "") + "Cargo.lock"
|
|
2500
2489
|
);
|
|
2501
2490
|
if (cargoLockFiles.length) {
|
|
2502
|
-
for (
|
|
2491
|
+
for (const f of cargoLockFiles) {
|
|
2503
2492
|
if (DEBUG_MODE) {
|
|
2504
2493
|
console.log(`Parsing ${f}`);
|
|
2505
2494
|
}
|
|
@@ -2523,7 +2512,7 @@ const createRustBom = async (path, options) => {
|
|
|
2523
2512
|
* @param path to the project
|
|
2524
2513
|
* @param options Parse options from the cli
|
|
2525
2514
|
*/
|
|
2526
|
-
const createDartBom = async (path, options) => {
|
|
2515
|
+
export const createDartBom = async (path, options) => {
|
|
2527
2516
|
const pubFiles = getAllFiles(
|
|
2528
2517
|
path,
|
|
2529
2518
|
(options.multiProject ? "**/" : "") + "pubspec.lock"
|
|
@@ -2534,7 +2523,7 @@ const createDartBom = async (path, options) => {
|
|
|
2534
2523
|
);
|
|
2535
2524
|
let pkgList = [];
|
|
2536
2525
|
if (pubFiles.length) {
|
|
2537
|
-
for (
|
|
2526
|
+
for (const f of pubFiles) {
|
|
2538
2527
|
if (DEBUG_MODE) {
|
|
2539
2528
|
console.log(`Parsing ${f}`);
|
|
2540
2529
|
}
|
|
@@ -2549,12 +2538,12 @@ const createDartBom = async (path, options) => {
|
|
|
2549
2538
|
filename: pubFiles.join(", ")
|
|
2550
2539
|
});
|
|
2551
2540
|
} else if (pubSpecYamlFiles.length) {
|
|
2552
|
-
for (
|
|
2541
|
+
for (const f of pubSpecYamlFiles) {
|
|
2553
2542
|
if (DEBUG_MODE) {
|
|
2554
2543
|
console.log(`Parsing ${f}`);
|
|
2555
2544
|
}
|
|
2556
2545
|
const pubYamlData = readFileSync(f, { encoding: "utf-8" });
|
|
2557
|
-
const dlist =
|
|
2546
|
+
const dlist = parsePubYamlData(pubYamlData);
|
|
2558
2547
|
if (dlist && dlist.length) {
|
|
2559
2548
|
pkgList = pkgList.concat(dlist);
|
|
2560
2549
|
}
|
|
@@ -2574,7 +2563,7 @@ const createDartBom = async (path, options) => {
|
|
|
2574
2563
|
* @param path to the project
|
|
2575
2564
|
* @param options Parse options from the cli
|
|
2576
2565
|
*/
|
|
2577
|
-
const createCppBom = async (path, options) => {
|
|
2566
|
+
export const createCppBom = async (path, options) => {
|
|
2578
2567
|
const conanLockFiles = getAllFiles(
|
|
2579
2568
|
path,
|
|
2580
2569
|
(options.multiProject ? "**/" : "") + "conan.lock"
|
|
@@ -2585,12 +2574,12 @@ const createCppBom = async (path, options) => {
|
|
|
2585
2574
|
);
|
|
2586
2575
|
let pkgList = [];
|
|
2587
2576
|
if (conanLockFiles.length) {
|
|
2588
|
-
for (
|
|
2577
|
+
for (const f of conanLockFiles) {
|
|
2589
2578
|
if (DEBUG_MODE) {
|
|
2590
2579
|
console.log(`Parsing ${f}`);
|
|
2591
2580
|
}
|
|
2592
2581
|
const conanLockData = readFileSync(f, { encoding: "utf-8" });
|
|
2593
|
-
const dlist =
|
|
2582
|
+
const dlist = parseConanLockData(conanLockData);
|
|
2594
2583
|
if (dlist && dlist.length) {
|
|
2595
2584
|
pkgList = pkgList.concat(dlist);
|
|
2596
2585
|
}
|
|
@@ -2600,12 +2589,12 @@ const createCppBom = async (path, options) => {
|
|
|
2600
2589
|
filename: conanLockFiles.join(", ")
|
|
2601
2590
|
});
|
|
2602
2591
|
} else if (conanFiles.length) {
|
|
2603
|
-
for (
|
|
2592
|
+
for (const f of conanFiles) {
|
|
2604
2593
|
if (DEBUG_MODE) {
|
|
2605
2594
|
console.log(`Parsing ${f}`);
|
|
2606
2595
|
}
|
|
2607
2596
|
const conanData = readFileSync(f, { encoding: "utf-8" });
|
|
2608
|
-
const dlist =
|
|
2597
|
+
const dlist = parseConanData(conanData);
|
|
2609
2598
|
if (dlist && dlist.length) {
|
|
2610
2599
|
pkgList = pkgList.concat(dlist);
|
|
2611
2600
|
}
|
|
@@ -2625,7 +2614,7 @@ const createCppBom = async (path, options) => {
|
|
|
2625
2614
|
* @param path to the project
|
|
2626
2615
|
* @param options Parse options from the cli
|
|
2627
2616
|
*/
|
|
2628
|
-
const createClojureBom =
|
|
2617
|
+
export const createClojureBom = (path, options) => {
|
|
2629
2618
|
const ednFiles = getAllFiles(
|
|
2630
2619
|
path,
|
|
2631
2620
|
(options.multiProject ? "**/" : "") + "deps.edn"
|
|
@@ -2640,7 +2629,7 @@ const createClojureBom = async (path, options) => {
|
|
|
2640
2629
|
if (process.env.LEIN_ARGS) {
|
|
2641
2630
|
LEIN_ARGS = process.env.LEIN_ARGS.split(" ");
|
|
2642
2631
|
}
|
|
2643
|
-
for (
|
|
2632
|
+
for (const f of leinFiles) {
|
|
2644
2633
|
if (DEBUG_MODE) {
|
|
2645
2634
|
console.log(`Parsing ${f}`);
|
|
2646
2635
|
}
|
|
@@ -2690,7 +2679,7 @@ const createClojureBom = async (path, options) => {
|
|
|
2690
2679
|
if (process.env.CLJ_ARGS) {
|
|
2691
2680
|
CLJ_ARGS = process.env.CLJ_ARGS.split(" ");
|
|
2692
2681
|
}
|
|
2693
|
-
for (
|
|
2682
|
+
for (const f of ednFiles) {
|
|
2694
2683
|
const basePath = dirname(f);
|
|
2695
2684
|
console.log("Executing", CLJ_CMD, CLJ_ARGS.join(" "), "in", basePath);
|
|
2696
2685
|
const result = spawnSync(CLJ_CMD, CLJ_ARGS, {
|
|
@@ -2743,19 +2732,19 @@ const createClojureBom = async (path, options) => {
|
|
|
2743
2732
|
* @param path to the project
|
|
2744
2733
|
* @param options Parse options from the cli
|
|
2745
2734
|
*/
|
|
2746
|
-
const createHaskellBom = async (path, options) => {
|
|
2735
|
+
export const createHaskellBom = async (path, options) => {
|
|
2747
2736
|
const cabalFiles = getAllFiles(
|
|
2748
2737
|
path,
|
|
2749
2738
|
(options.multiProject ? "**/" : "") + "cabal.project.freeze"
|
|
2750
2739
|
);
|
|
2751
2740
|
let pkgList = [];
|
|
2752
2741
|
if (cabalFiles.length) {
|
|
2753
|
-
for (
|
|
2742
|
+
for (const f of cabalFiles) {
|
|
2754
2743
|
if (DEBUG_MODE) {
|
|
2755
2744
|
console.log(`Parsing ${f}`);
|
|
2756
2745
|
}
|
|
2757
2746
|
const cabalData = readFileSync(f, { encoding: "utf-8" });
|
|
2758
|
-
const dlist =
|
|
2747
|
+
const dlist = parseCabalData(cabalData);
|
|
2759
2748
|
if (dlist && dlist.length) {
|
|
2760
2749
|
pkgList = pkgList.concat(dlist);
|
|
2761
2750
|
}
|
|
@@ -2774,19 +2763,19 @@ const createHaskellBom = async (path, options) => {
|
|
|
2774
2763
|
* @param path to the project
|
|
2775
2764
|
* @param options Parse options from the cli
|
|
2776
2765
|
*/
|
|
2777
|
-
const createElixirBom = async (path, options) => {
|
|
2766
|
+
export const createElixirBom = async (path, options) => {
|
|
2778
2767
|
const mixFiles = getAllFiles(
|
|
2779
2768
|
path,
|
|
2780
2769
|
(options.multiProject ? "**/" : "") + "mix.lock"
|
|
2781
2770
|
);
|
|
2782
2771
|
let pkgList = [];
|
|
2783
2772
|
if (mixFiles.length) {
|
|
2784
|
-
for (
|
|
2773
|
+
for (const f of mixFiles) {
|
|
2785
2774
|
if (DEBUG_MODE) {
|
|
2786
2775
|
console.log(`Parsing ${f}`);
|
|
2787
2776
|
}
|
|
2788
2777
|
const mixData = readFileSync(f, { encoding: "utf-8" });
|
|
2789
|
-
const dlist =
|
|
2778
|
+
const dlist = parseMixLockData(mixData);
|
|
2790
2779
|
if (dlist && dlist.length) {
|
|
2791
2780
|
pkgList = pkgList.concat(dlist);
|
|
2792
2781
|
}
|
|
@@ -2805,16 +2794,16 @@ const createElixirBom = async (path, options) => {
|
|
|
2805
2794
|
* @param path to the project
|
|
2806
2795
|
* @param options Parse options from the cli
|
|
2807
2796
|
*/
|
|
2808
|
-
const createGitHubBom = async (path, options) => {
|
|
2797
|
+
export const createGitHubBom = async (path, options) => {
|
|
2809
2798
|
const ghactionFiles = getAllFiles(path, ".github/workflows/" + "*.yml");
|
|
2810
2799
|
let pkgList = [];
|
|
2811
2800
|
if (ghactionFiles.length) {
|
|
2812
|
-
for (
|
|
2801
|
+
for (const f of ghactionFiles) {
|
|
2813
2802
|
if (DEBUG_MODE) {
|
|
2814
2803
|
console.log(`Parsing ${f}`);
|
|
2815
2804
|
}
|
|
2816
2805
|
const ghwData = readFileSync(f, { encoding: "utf-8" });
|
|
2817
|
-
const dlist =
|
|
2806
|
+
const dlist = parseGitHubWorkflowData(ghwData);
|
|
2818
2807
|
if (dlist && dlist.length) {
|
|
2819
2808
|
pkgList = pkgList.concat(dlist);
|
|
2820
2809
|
}
|
|
@@ -2833,16 +2822,16 @@ const createGitHubBom = async (path, options) => {
|
|
|
2833
2822
|
* @param path to the project
|
|
2834
2823
|
* @param options Parse options from the cli
|
|
2835
2824
|
*/
|
|
2836
|
-
const createCloudBuildBom = async (path, options) => {
|
|
2825
|
+
export const createCloudBuildBom = async (path, options) => {
|
|
2837
2826
|
const cbFiles = getAllFiles(path, "cloudbuild.yml");
|
|
2838
2827
|
let pkgList = [];
|
|
2839
2828
|
if (cbFiles.length) {
|
|
2840
|
-
for (
|
|
2829
|
+
for (const f of cbFiles) {
|
|
2841
2830
|
if (DEBUG_MODE) {
|
|
2842
2831
|
console.log(`Parsing ${f}`);
|
|
2843
2832
|
}
|
|
2844
2833
|
const cbwData = readFileSync(f, { encoding: "utf-8" });
|
|
2845
|
-
const dlist =
|
|
2834
|
+
const dlist = parseCloudBuildData(cbwData);
|
|
2846
2835
|
if (dlist && dlist.length) {
|
|
2847
2836
|
pkgList = pkgList.concat(dlist);
|
|
2848
2837
|
}
|
|
@@ -2861,7 +2850,7 @@ const createCloudBuildBom = async (path, options) => {
|
|
|
2861
2850
|
* @param path to the project
|
|
2862
2851
|
* @param options Parse options from the cli
|
|
2863
2852
|
*/
|
|
2864
|
-
const createOSBom =
|
|
2853
|
+
export const createOSBom = (path, options) => {
|
|
2865
2854
|
console.warn(
|
|
2866
2855
|
"About to generate SBoM for the current OS installation. This would take several minutes ..."
|
|
2867
2856
|
);
|
|
@@ -2893,7 +2882,7 @@ const createOSBom = async (path, options) => {
|
|
|
2893
2882
|
allLayersDir: options.allLayersExplodedDir,
|
|
2894
2883
|
allLayersExplodedDir: options.allLayersExplodedDir
|
|
2895
2884
|
};
|
|
2896
|
-
|
|
2885
|
+
const pkgPathList = [];
|
|
2897
2886
|
if (options.deep) {
|
|
2898
2887
|
getPkgPathList(exportData, undefined);
|
|
2899
2888
|
}
|
|
@@ -2906,15 +2895,15 @@ const createOSBom = async (path, options) => {
|
|
|
2906
2895
|
* @param path to the project
|
|
2907
2896
|
* @param options Parse options from the cli
|
|
2908
2897
|
*/
|
|
2909
|
-
const createJenkinsBom = async (path, options) => {
|
|
2898
|
+
export const createJenkinsBom = async (path, options) => {
|
|
2910
2899
|
let pkgList = [];
|
|
2911
2900
|
const hpiFiles = getAllFiles(
|
|
2912
2901
|
path,
|
|
2913
2902
|
(options.multiProject ? "**/" : "") + "*.hpi"
|
|
2914
2903
|
);
|
|
2915
|
-
|
|
2904
|
+
const tempDir = mkdtempSync(join(tmpdir(), "hpi-deps-"));
|
|
2916
2905
|
if (hpiFiles.length) {
|
|
2917
|
-
for (
|
|
2906
|
+
for (const f of hpiFiles) {
|
|
2918
2907
|
if (DEBUG_MODE) {
|
|
2919
2908
|
console.log(`Parsing ${f}`);
|
|
2920
2909
|
}
|
|
@@ -2926,7 +2915,7 @@ const createJenkinsBom = async (path, options) => {
|
|
|
2926
2915
|
}
|
|
2927
2916
|
const jsFiles = getAllFiles(tempDir, "**/*.js");
|
|
2928
2917
|
if (jsFiles.length) {
|
|
2929
|
-
for (
|
|
2918
|
+
for (const f of jsFiles) {
|
|
2930
2919
|
if (DEBUG_MODE) {
|
|
2931
2920
|
console.log(`Parsing ${f}`);
|
|
2932
2921
|
}
|
|
@@ -2954,19 +2943,19 @@ const createJenkinsBom = async (path, options) => {
|
|
|
2954
2943
|
* @param path to the project
|
|
2955
2944
|
* @param options Parse options from the cli
|
|
2956
2945
|
*/
|
|
2957
|
-
const createHelmBom = async (path, options) => {
|
|
2946
|
+
export const createHelmBom = async (path, options) => {
|
|
2958
2947
|
let pkgList = [];
|
|
2959
2948
|
const yamlFiles = getAllFiles(
|
|
2960
2949
|
path,
|
|
2961
2950
|
(options.multiProject ? "**/" : "") + "*.yaml"
|
|
2962
2951
|
);
|
|
2963
2952
|
if (yamlFiles.length) {
|
|
2964
|
-
for (
|
|
2953
|
+
for (const f of yamlFiles) {
|
|
2965
2954
|
if (DEBUG_MODE) {
|
|
2966
2955
|
console.log(`Parsing ${f}`);
|
|
2967
2956
|
}
|
|
2968
2957
|
const helmData = readFileSync(f, { encoding: "utf-8" });
|
|
2969
|
-
const dlist =
|
|
2958
|
+
const dlist = parseHelmYamlData(helmData);
|
|
2970
2959
|
if (dlist && dlist.length) {
|
|
2971
2960
|
pkgList = pkgList.concat(dlist);
|
|
2972
2961
|
}
|
|
@@ -2985,7 +2974,7 @@ const createHelmBom = async (path, options) => {
|
|
|
2985
2974
|
* @param path to the project
|
|
2986
2975
|
* @param options Parse options from the cli
|
|
2987
2976
|
*/
|
|
2988
|
-
const createSwiftBom =
|
|
2977
|
+
export const createSwiftBom = (path, options) => {
|
|
2989
2978
|
const swiftFiles = getAllFiles(
|
|
2990
2979
|
path,
|
|
2991
2980
|
(options.multiProject ? "**/" : "") + "Package*.swift"
|
|
@@ -2997,9 +2986,9 @@ const createSwiftBom = async (path, options) => {
|
|
|
2997
2986
|
let pkgList = [];
|
|
2998
2987
|
let dependencies = [];
|
|
2999
2988
|
let parentComponent = {};
|
|
3000
|
-
|
|
2989
|
+
const completedPath = [];
|
|
3001
2990
|
if (pkgResolvedFiles.length) {
|
|
3002
|
-
for (
|
|
2991
|
+
for (const f of pkgResolvedFiles) {
|
|
3003
2992
|
if (!parentComponent || !Object.keys(parentComponent).length) {
|
|
3004
2993
|
parentComponent = createDefaultParentComponent(f);
|
|
3005
2994
|
}
|
|
@@ -3013,7 +3002,7 @@ const createSwiftBom = async (path, options) => {
|
|
|
3013
3002
|
}
|
|
3014
3003
|
}
|
|
3015
3004
|
if (swiftFiles.length) {
|
|
3016
|
-
for (
|
|
3005
|
+
for (const f of swiftFiles) {
|
|
3017
3006
|
const basePath = dirname(f);
|
|
3018
3007
|
if (completedPath.includes(basePath)) {
|
|
3019
3008
|
continue;
|
|
@@ -3071,16 +3060,16 @@ const createSwiftBom = async (path, options) => {
|
|
|
3071
3060
|
* @param path to the project
|
|
3072
3061
|
* @param options Parse options from the cli
|
|
3073
3062
|
*/
|
|
3074
|
-
const createContainerSpecLikeBom = async (path, options) => {
|
|
3063
|
+
export const createContainerSpecLikeBom = async (path, options) => {
|
|
3075
3064
|
let services = [];
|
|
3076
|
-
|
|
3065
|
+
const ociSpecs = [];
|
|
3077
3066
|
let components = [];
|
|
3078
3067
|
let componentsXmls = [];
|
|
3079
|
-
|
|
3068
|
+
const parentComponent = {};
|
|
3080
3069
|
let dependencies = [];
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3070
|
+
const doneimages = [];
|
|
3071
|
+
const doneservices = [];
|
|
3072
|
+
const origProjectType = options.projectType;
|
|
3084
3073
|
let dcFiles = getAllFiles(
|
|
3085
3074
|
path,
|
|
3086
3075
|
(options.multiProject ? "**/" : "") + "*.yml"
|
|
@@ -3093,7 +3082,7 @@ const createContainerSpecLikeBom = async (path, options) => {
|
|
|
3093
3082
|
path,
|
|
3094
3083
|
(options.multiProject ? "**/" : "") + "open*.json"
|
|
3095
3084
|
);
|
|
3096
|
-
|
|
3085
|
+
const oapiYamlFiles = getAllFiles(
|
|
3097
3086
|
path,
|
|
3098
3087
|
(options.multiProject ? "**/" : "") + "open*.yaml"
|
|
3099
3088
|
);
|
|
@@ -3107,18 +3096,18 @@ const createContainerSpecLikeBom = async (path, options) => {
|
|
|
3107
3096
|
const privadoFiles = getAllFiles(path, ".privado/" + "*.json");
|
|
3108
3097
|
// parse yaml manifest files
|
|
3109
3098
|
if (dcFiles.length) {
|
|
3110
|
-
for (
|
|
3099
|
+
for (const f of dcFiles) {
|
|
3111
3100
|
if (DEBUG_MODE) {
|
|
3112
3101
|
console.log(`Parsing ${f}`);
|
|
3113
3102
|
}
|
|
3114
3103
|
const dcData = readFileSync(f, { encoding: "utf-8" });
|
|
3115
|
-
const imglist =
|
|
3104
|
+
const imglist = parseContainerSpecData(dcData);
|
|
3116
3105
|
if (imglist && imglist.length) {
|
|
3117
3106
|
if (DEBUG_MODE) {
|
|
3118
3107
|
console.log("Images identified in", f, "are", imglist);
|
|
3119
3108
|
}
|
|
3120
3109
|
for (const img of imglist) {
|
|
3121
|
-
|
|
3110
|
+
const commonProperties = [
|
|
3122
3111
|
{
|
|
3123
3112
|
name: "SrcFile",
|
|
3124
3113
|
value: f
|
|
@@ -3239,12 +3228,12 @@ const createContainerSpecLikeBom = async (path, options) => {
|
|
|
3239
3228
|
} // if
|
|
3240
3229
|
// Parse openapi files
|
|
3241
3230
|
if (oapiFiles.length) {
|
|
3242
|
-
for (
|
|
3231
|
+
for (const af of oapiFiles) {
|
|
3243
3232
|
if (DEBUG_MODE) {
|
|
3244
3233
|
console.log(`Parsing ${af}`);
|
|
3245
3234
|
}
|
|
3246
3235
|
const oaData = readFileSync(af, { encoding: "utf-8" });
|
|
3247
|
-
const servlist =
|
|
3236
|
+
const servlist = parseOpenapiSpecData(oaData);
|
|
3248
3237
|
if (servlist && servlist.length) {
|
|
3249
3238
|
// Inject SrcFile property
|
|
3250
3239
|
for (const se of servlist) {
|
|
@@ -3265,14 +3254,14 @@ const createContainerSpecLikeBom = async (path, options) => {
|
|
|
3265
3254
|
"Enriching your SBoM with information from privado.ai scan reports"
|
|
3266
3255
|
);
|
|
3267
3256
|
let rows = [["Classification", "Flow"]];
|
|
3268
|
-
|
|
3257
|
+
const config = {
|
|
3269
3258
|
header: {
|
|
3270
3259
|
alignment: "center",
|
|
3271
3260
|
content: "Data Privacy Insights from privado.ai"
|
|
3272
3261
|
},
|
|
3273
3262
|
columns: [{ width: 50 }, { width: 10 }]
|
|
3274
3263
|
};
|
|
3275
|
-
for (
|
|
3264
|
+
for (const f of privadoFiles) {
|
|
3276
3265
|
if (DEBUG_MODE) {
|
|
3277
3266
|
console.log(`Parsing ${f}`);
|
|
3278
3267
|
}
|
|
@@ -3281,14 +3270,14 @@ const createContainerSpecLikeBom = async (path, options) => {
|
|
|
3281
3270
|
if (servlist.length) {
|
|
3282
3271
|
const aservice = servlist[0];
|
|
3283
3272
|
if (aservice.data) {
|
|
3284
|
-
for (
|
|
3273
|
+
for (const d of aservice.data) {
|
|
3285
3274
|
rows.push([d.classification, d.flow]);
|
|
3286
3275
|
}
|
|
3287
3276
|
console.log(table(rows, config));
|
|
3288
3277
|
}
|
|
3289
3278
|
if (aservice.endpoints) {
|
|
3290
3279
|
rows = [["Leaky Endpoints"]];
|
|
3291
|
-
for (
|
|
3280
|
+
for (const e of aservice.endpoints) {
|
|
3292
3281
|
rows.push([e]);
|
|
3293
3282
|
}
|
|
3294
3283
|
console.log(
|
|
@@ -3350,7 +3339,7 @@ const createContainerSpecLikeBom = async (path, options) => {
|
|
|
3350
3339
|
* @param path to the project
|
|
3351
3340
|
* @param options Parse options from the cli
|
|
3352
3341
|
*/
|
|
3353
|
-
const createPHPBom =
|
|
3342
|
+
export const createPHPBom = (path, options) => {
|
|
3354
3343
|
const composerJsonFiles = getAllFiles(
|
|
3355
3344
|
path,
|
|
3356
3345
|
(options.multiProject ? "**/" : "") + "composer.json"
|
|
@@ -3383,14 +3372,14 @@ const createPHPBom = async (path, options) => {
|
|
|
3383
3372
|
if (DEBUG_MODE) {
|
|
3384
3373
|
console.log("Parsing version", versionResult.stdout);
|
|
3385
3374
|
}
|
|
3386
|
-
|
|
3375
|
+
const tmpV = undefined;
|
|
3387
3376
|
if (versionResult && versionResult.stdout) {
|
|
3388
3377
|
versionResult.stdout.split(" ");
|
|
3389
3378
|
}
|
|
3390
3379
|
if (tmpV && tmpV.length > 1) {
|
|
3391
3380
|
composerVersion = tmpV[1];
|
|
3392
3381
|
}
|
|
3393
|
-
for (
|
|
3382
|
+
for (const f of composerJsonFiles) {
|
|
3394
3383
|
const basePath = dirname(f);
|
|
3395
3384
|
let args = [];
|
|
3396
3385
|
if (composerVersion && !composerVersion.startsWith("1")) {
|
|
@@ -3416,11 +3405,11 @@ const createPHPBom = async (path, options) => {
|
|
|
3416
3405
|
(options.multiProject ? "**/" : "") + "composer.lock"
|
|
3417
3406
|
);
|
|
3418
3407
|
if (composerLockFiles.length) {
|
|
3419
|
-
for (
|
|
3408
|
+
for (const f of composerLockFiles) {
|
|
3420
3409
|
if (DEBUG_MODE) {
|
|
3421
3410
|
console.log(`Parsing ${f}`);
|
|
3422
3411
|
}
|
|
3423
|
-
|
|
3412
|
+
const dlist = parseComposerLock(f);
|
|
3424
3413
|
if (dlist && dlist.length) {
|
|
3425
3414
|
pkgList = pkgList.concat(dlist);
|
|
3426
3415
|
}
|
|
@@ -3439,7 +3428,7 @@ const createPHPBom = async (path, options) => {
|
|
|
3439
3428
|
* @param path to the project
|
|
3440
3429
|
* @param options Parse options from the cli
|
|
3441
3430
|
*/
|
|
3442
|
-
const createRubyBom = async (path, options) => {
|
|
3431
|
+
export const createRubyBom = async (path, options) => {
|
|
3443
3432
|
const gemFiles = getAllFiles(
|
|
3444
3433
|
path,
|
|
3445
3434
|
(options.multiProject ? "**/" : "") + "Gemfile"
|
|
@@ -3450,9 +3439,9 @@ const createRubyBom = async (path, options) => {
|
|
|
3450
3439
|
);
|
|
3451
3440
|
let pkgList = [];
|
|
3452
3441
|
const gemFileMode = gemFiles.length;
|
|
3453
|
-
|
|
3442
|
+
const gemLockMode = gemLockFiles.length;
|
|
3454
3443
|
if (gemFileMode && !gemLockMode && options.installDeps) {
|
|
3455
|
-
for (
|
|
3444
|
+
for (const f of gemFiles) {
|
|
3456
3445
|
const basePath = dirname(f);
|
|
3457
3446
|
console.log("Executing 'bundle install' in", basePath);
|
|
3458
3447
|
const result = spawnSync("bundle", ["install"], {
|
|
@@ -3473,11 +3462,11 @@ const createRubyBom = async (path, options) => {
|
|
|
3473
3462
|
(options.multiProject ? "**/" : "") + "Gemfile.lock"
|
|
3474
3463
|
);
|
|
3475
3464
|
if (gemLockFiles.length) {
|
|
3476
|
-
for (
|
|
3465
|
+
for (const f of gemLockFiles) {
|
|
3477
3466
|
if (DEBUG_MODE) {
|
|
3478
3467
|
console.log(`Parsing ${f}`);
|
|
3479
3468
|
}
|
|
3480
|
-
|
|
3469
|
+
const gemLockData = readFileSync(f, { encoding: "utf-8" });
|
|
3481
3470
|
const dlist = await parseGemfileLockData(gemLockData);
|
|
3482
3471
|
if (dlist && dlist.length) {
|
|
3483
3472
|
pkgList = pkgList.concat(dlist);
|
|
@@ -3497,8 +3486,9 @@ const createRubyBom = async (path, options) => {
|
|
|
3497
3486
|
* @param path to the project
|
|
3498
3487
|
* @param options Parse options from the cli
|
|
3499
3488
|
*/
|
|
3500
|
-
const createCsharpBom = async (path, options) => {
|
|
3489
|
+
export const createCsharpBom = async (path, options) => {
|
|
3501
3490
|
let manifestFiles = [];
|
|
3491
|
+
let pkgData = undefined;
|
|
3502
3492
|
const csProjFiles = getAllFiles(
|
|
3503
3493
|
path,
|
|
3504
3494
|
(options.multiProject ? "**/" : "") + "*.csproj"
|
|
@@ -3522,7 +3512,7 @@ const createCsharpBom = async (path, options) => {
|
|
|
3522
3512
|
let pkgList = [];
|
|
3523
3513
|
if (nupkgFiles.length) {
|
|
3524
3514
|
manifestFiles = manifestFiles.concat(nupkgFiles);
|
|
3525
|
-
for (
|
|
3515
|
+
for (const nf of nupkgFiles) {
|
|
3526
3516
|
if (DEBUG_MODE) {
|
|
3527
3517
|
console.log(`Parsing ${nf}`);
|
|
3528
3518
|
}
|
|
@@ -3535,11 +3525,11 @@ const createCsharpBom = async (path, options) => {
|
|
|
3535
3525
|
// project.assets.json parsing
|
|
3536
3526
|
if (projAssetsFiles.length) {
|
|
3537
3527
|
manifestFiles = manifestFiles.concat(projAssetsFiles);
|
|
3538
|
-
for (
|
|
3528
|
+
for (const af of projAssetsFiles) {
|
|
3539
3529
|
if (DEBUG_MODE) {
|
|
3540
3530
|
console.log(`Parsing ${af}`);
|
|
3541
3531
|
}
|
|
3542
|
-
|
|
3532
|
+
pkgData = readFileSync(af, { encoding: "utf-8" });
|
|
3543
3533
|
const dlist = await parseCsProjAssetsData(pkgData);
|
|
3544
3534
|
if (dlist && dlist.length) {
|
|
3545
3535
|
pkgList = pkgList.concat(dlist);
|
|
@@ -3548,11 +3538,11 @@ const createCsharpBom = async (path, options) => {
|
|
|
3548
3538
|
} else if (pkgLockFiles.length) {
|
|
3549
3539
|
manifestFiles = manifestFiles.concat(pkgLockFiles);
|
|
3550
3540
|
// packages.lock.json from nuget
|
|
3551
|
-
for (
|
|
3541
|
+
for (const af of pkgLockFiles) {
|
|
3552
3542
|
if (DEBUG_MODE) {
|
|
3553
3543
|
console.log(`Parsing ${af}`);
|
|
3554
3544
|
}
|
|
3555
|
-
|
|
3545
|
+
pkgData = readFileSync(af, { encoding: "utf-8" });
|
|
3556
3546
|
const dlist = await parseCsPkgLockData(pkgData);
|
|
3557
3547
|
if (dlist && dlist.length) {
|
|
3558
3548
|
pkgList = pkgList.concat(dlist);
|
|
@@ -3561,11 +3551,11 @@ const createCsharpBom = async (path, options) => {
|
|
|
3561
3551
|
} else if (pkgConfigFiles.length) {
|
|
3562
3552
|
manifestFiles = manifestFiles.concat(pkgConfigFiles);
|
|
3563
3553
|
// packages.config parsing
|
|
3564
|
-
for (
|
|
3554
|
+
for (const f of pkgConfigFiles) {
|
|
3565
3555
|
if (DEBUG_MODE) {
|
|
3566
3556
|
console.log(`Parsing ${f}`);
|
|
3567
3557
|
}
|
|
3568
|
-
|
|
3558
|
+
pkgData = readFileSync(f, { encoding: "utf-8" });
|
|
3569
3559
|
// Remove byte order mark
|
|
3570
3560
|
if (pkgData.charCodeAt(0) === 0xfeff) {
|
|
3571
3561
|
pkgData = pkgData.slice(1);
|
|
@@ -3578,7 +3568,7 @@ const createCsharpBom = async (path, options) => {
|
|
|
3578
3568
|
} else if (csProjFiles.length) {
|
|
3579
3569
|
manifestFiles = manifestFiles.concat(csProjFiles);
|
|
3580
3570
|
// .csproj parsing
|
|
3581
|
-
for (
|
|
3571
|
+
for (const f of csProjFiles) {
|
|
3582
3572
|
if (DEBUG_MODE) {
|
|
3583
3573
|
console.log(`Parsing ${f}`);
|
|
3584
3574
|
}
|
|
@@ -3602,9 +3592,9 @@ const createCsharpBom = async (path, options) => {
|
|
|
3602
3592
|
return {};
|
|
3603
3593
|
};
|
|
3604
3594
|
|
|
3605
|
-
const mergeDependencies = (dependencies, newDependencies) => {
|
|
3595
|
+
export const mergeDependencies = (dependencies, newDependencies) => {
|
|
3606
3596
|
const deps_map = {};
|
|
3607
|
-
|
|
3597
|
+
const combinedDeps = dependencies.concat(newDependencies || []);
|
|
3608
3598
|
for (const adep of combinedDeps) {
|
|
3609
3599
|
if (!deps_map[adep.ref]) {
|
|
3610
3600
|
deps_map[adep.ref] = new Set();
|
|
@@ -3613,7 +3603,7 @@ const mergeDependencies = (dependencies, newDependencies) => {
|
|
|
3613
3603
|
deps_map[adep.ref].add(eachDepends);
|
|
3614
3604
|
}
|
|
3615
3605
|
}
|
|
3616
|
-
|
|
3606
|
+
const retlist = [];
|
|
3617
3607
|
for (const akey of Object.keys(deps_map)) {
|
|
3618
3608
|
retlist.push({
|
|
3619
3609
|
ref: akey,
|
|
@@ -3622,13 +3612,11 @@ const mergeDependencies = (dependencies, newDependencies) => {
|
|
|
3622
3612
|
}
|
|
3623
3613
|
return retlist;
|
|
3624
3614
|
};
|
|
3625
|
-
const _mergeDependencies = mergeDependencies;
|
|
3626
|
-
export { _mergeDependencies as mergeDependencies };
|
|
3627
3615
|
|
|
3628
|
-
const trimComponents = (components, format) => {
|
|
3616
|
+
export const trimComponents = (components, format) => {
|
|
3629
3617
|
const keyCache = {};
|
|
3630
3618
|
const filteredComponents = [];
|
|
3631
|
-
for (
|
|
3619
|
+
for (const comp of components) {
|
|
3632
3620
|
if (format === "xml" && comp.component) {
|
|
3633
3621
|
if (!keyCache[comp.component.purl]) {
|
|
3634
3622
|
keyCache[comp.component.purl] = true;
|
|
@@ -3643,10 +3631,8 @@ const trimComponents = (components, format) => {
|
|
|
3643
3631
|
}
|
|
3644
3632
|
return filteredComponents;
|
|
3645
3633
|
};
|
|
3646
|
-
const _trimComponents = trimComponents;
|
|
3647
|
-
export { _trimComponents as trimComponents };
|
|
3648
3634
|
|
|
3649
|
-
const dedupeBom = (
|
|
3635
|
+
export const dedupeBom = (
|
|
3650
3636
|
options,
|
|
3651
3637
|
components,
|
|
3652
3638
|
componentsXmls,
|
|
@@ -3694,8 +3680,6 @@ const dedupeBom = (
|
|
|
3694
3680
|
}
|
|
3695
3681
|
};
|
|
3696
3682
|
};
|
|
3697
|
-
const _dedupeBom = dedupeBom;
|
|
3698
|
-
export { _dedupeBom as dedupeBom };
|
|
3699
3683
|
|
|
3700
3684
|
/**
|
|
3701
3685
|
* Function to create bom string for all languages
|
|
@@ -3703,7 +3687,7 @@ export { _dedupeBom as dedupeBom };
|
|
|
3703
3687
|
* @param pathList list of to the project
|
|
3704
3688
|
* @param options Parse options from the cli
|
|
3705
3689
|
*/
|
|
3706
|
-
const createMultiXBom = async (pathList, options) => {
|
|
3690
|
+
export const createMultiXBom = async (pathList, options) => {
|
|
3707
3691
|
let components = [];
|
|
3708
3692
|
let dependencies = [];
|
|
3709
3693
|
let componentsXmls = [];
|
|
@@ -3741,7 +3725,7 @@ const createMultiXBom = async (pathList, options) => {
|
|
|
3741
3725
|
);
|
|
3742
3726
|
}
|
|
3743
3727
|
}
|
|
3744
|
-
for (
|
|
3728
|
+
for (const path of pathList) {
|
|
3745
3729
|
if (DEBUG_MODE) {
|
|
3746
3730
|
console.log("Scanning", path);
|
|
3747
3731
|
}
|
|
@@ -3830,7 +3814,7 @@ const createMultiXBom = async (pathList, options) => {
|
|
|
3830
3814
|
listComponents(options, {}, bomData.bomJson.components, "cargo", "xml")
|
|
3831
3815
|
);
|
|
3832
3816
|
}
|
|
3833
|
-
bomData =
|
|
3817
|
+
bomData = createPHPBom(path, options);
|
|
3834
3818
|
if (bomData && bomData.bomJson && bomData.bomJson.components) {
|
|
3835
3819
|
if (DEBUG_MODE) {
|
|
3836
3820
|
console.log(
|
|
@@ -3954,7 +3938,7 @@ const createMultiXBom = async (pathList, options) => {
|
|
|
3954
3938
|
listComponents(options, {}, bomData.bomJson.components, "conan", "xml")
|
|
3955
3939
|
);
|
|
3956
3940
|
}
|
|
3957
|
-
bomData =
|
|
3941
|
+
bomData = createClojureBom(path, options);
|
|
3958
3942
|
if (bomData && bomData.bomJson && bomData.bomJson.components) {
|
|
3959
3943
|
if (DEBUG_MODE) {
|
|
3960
3944
|
console.log(
|
|
@@ -4014,7 +3998,7 @@ const createMultiXBom = async (pathList, options) => {
|
|
|
4014
3998
|
)
|
|
4015
3999
|
);
|
|
4016
4000
|
}
|
|
4017
|
-
bomData =
|
|
4001
|
+
bomData = createSwiftBom(path, options);
|
|
4018
4002
|
if (
|
|
4019
4003
|
bomData &&
|
|
4020
4004
|
bomData.bomJson &&
|
|
@@ -4035,30 +4019,23 @@ const createMultiXBom = async (pathList, options) => {
|
|
|
4035
4019
|
listComponents(options, {}, bomData.bomJson.components, "swift", "xml")
|
|
4036
4020
|
);
|
|
4037
4021
|
}
|
|
4038
|
-
//
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
);
|
|
4046
|
-
}
|
|
4047
|
-
components = components.concat(bomData.bomJson.components);
|
|
4048
|
-
dependencies = dependencies.concat(bomData.bomJson.dependencies);
|
|
4049
|
-
if (!parentComponent || !Object.keys(parentComponent).length) {
|
|
4050
|
-
parentComponent = bomData.parentComponent;
|
|
4051
|
-
}
|
|
4052
|
-
componentsXmls = componentsXmls.concat(
|
|
4053
|
-
listComponents(
|
|
4054
|
-
options,
|
|
4055
|
-
{},
|
|
4056
|
-
bomData.bomJson.components,
|
|
4057
|
-
"maven",
|
|
4058
|
-
"xml"
|
|
4059
|
-
)
|
|
4022
|
+
// Jar scanning is enabled by default
|
|
4023
|
+
// See #330
|
|
4024
|
+
bomData = createJarBom(path, options);
|
|
4025
|
+
if (bomData && bomData.bomJson && bomData.bomJson.components) {
|
|
4026
|
+
if (DEBUG_MODE) {
|
|
4027
|
+
console.log(
|
|
4028
|
+
`Found ${bomData.bomJson.components.length} jar packages at ${path}`
|
|
4060
4029
|
);
|
|
4061
4030
|
}
|
|
4031
|
+
components = components.concat(bomData.bomJson.components);
|
|
4032
|
+
dependencies = dependencies.concat(bomData.bomJson.dependencies);
|
|
4033
|
+
if (!parentComponent || !Object.keys(parentComponent).length) {
|
|
4034
|
+
parentComponent = bomData.parentComponent;
|
|
4035
|
+
}
|
|
4036
|
+
componentsXmls = componentsXmls.concat(
|
|
4037
|
+
listComponents(options, {}, bomData.bomJson.components, "maven", "xml")
|
|
4038
|
+
);
|
|
4062
4039
|
}
|
|
4063
4040
|
} // for
|
|
4064
4041
|
if (options.lastWorkingDir && options.lastWorkingDir !== "") {
|
|
@@ -4094,7 +4071,7 @@ const createMultiXBom = async (pathList, options) => {
|
|
|
4094
4071
|
* @param path to the project
|
|
4095
4072
|
* @param options Parse options from the cli
|
|
4096
4073
|
*/
|
|
4097
|
-
const createXBom = async (path, options) => {
|
|
4074
|
+
export const createXBom = async (path, options) => {
|
|
4098
4075
|
try {
|
|
4099
4076
|
accessSync(path, constants.R_OK);
|
|
4100
4077
|
} catch (err) {
|
|
@@ -4115,12 +4092,12 @@ const createXBom = async (path, options) => {
|
|
|
4115
4092
|
(options.multiProject ? "**/" : "") + "pom.xml"
|
|
4116
4093
|
);
|
|
4117
4094
|
// gradle
|
|
4118
|
-
|
|
4095
|
+
const gradleFiles = getAllFiles(
|
|
4119
4096
|
path,
|
|
4120
4097
|
(options.multiProject ? "**/" : "") + "build.gradle*"
|
|
4121
4098
|
);
|
|
4122
4099
|
// scala sbt
|
|
4123
|
-
|
|
4100
|
+
const sbtFiles = getAllFiles(
|
|
4124
4101
|
path,
|
|
4125
4102
|
(options.multiProject ? "**/" : "") + "{build.sbt,Build.scala}*"
|
|
4126
4103
|
);
|
|
@@ -4192,7 +4169,7 @@ const createXBom = async (path, options) => {
|
|
|
4192
4169
|
(options.multiProject ? "**/" : "") + "composer.lock"
|
|
4193
4170
|
);
|
|
4194
4171
|
if (composerJsonFiles.length || composerLockFiles.length) {
|
|
4195
|
-
return
|
|
4172
|
+
return createPHPBom(path, options);
|
|
4196
4173
|
}
|
|
4197
4174
|
|
|
4198
4175
|
// Ruby
|
|
@@ -4271,7 +4248,7 @@ const createXBom = async (path, options) => {
|
|
|
4271
4248
|
(options.multiProject ? "**/" : "") + "project.clj"
|
|
4272
4249
|
);
|
|
4273
4250
|
if (ednFiles.length || leinFiles.length) {
|
|
4274
|
-
return
|
|
4251
|
+
return createClojureBom(path, options);
|
|
4275
4252
|
}
|
|
4276
4253
|
|
|
4277
4254
|
// GitHub actions
|
|
@@ -4338,7 +4315,7 @@ const createXBom = async (path, options) => {
|
|
|
4338
4315
|
(options.multiProject ? "**/" : "") + "Package.resolved"
|
|
4339
4316
|
);
|
|
4340
4317
|
if (swiftFiles.length || pkgResolvedFiles.length) {
|
|
4341
|
-
return
|
|
4318
|
+
return createSwiftBom(path, options);
|
|
4342
4319
|
}
|
|
4343
4320
|
};
|
|
4344
4321
|
|
|
@@ -4474,20 +4451,20 @@ export const createBom = async (path, options) => {
|
|
|
4474
4451
|
return await createJavaBom(path, options);
|
|
4475
4452
|
case "jar":
|
|
4476
4453
|
options.multiProject = true;
|
|
4477
|
-
return
|
|
4454
|
+
return createJarBom(path, options);
|
|
4478
4455
|
case "gradle-index":
|
|
4479
4456
|
case "gradle-cache":
|
|
4480
4457
|
options.multiProject = true;
|
|
4481
|
-
return
|
|
4458
|
+
return createJarBom(GRADLE_CACHE_DIR, options);
|
|
4482
4459
|
case "sbt-index":
|
|
4483
4460
|
case "sbt-cache":
|
|
4484
4461
|
options.multiProject = true;
|
|
4485
|
-
return
|
|
4462
|
+
return createJarBom(SBT_CACHE_DIR, options);
|
|
4486
4463
|
case "maven-index":
|
|
4487
4464
|
case "maven-cache":
|
|
4488
4465
|
case "maven-repo":
|
|
4489
4466
|
options.multiProject = true;
|
|
4490
|
-
return
|
|
4467
|
+
return createJarBom(join(homedir(), ".m2", "repository"), options);
|
|
4491
4468
|
case "nodejs":
|
|
4492
4469
|
case "js":
|
|
4493
4470
|
case "javascript":
|
|
@@ -4510,7 +4487,7 @@ export const createBom = async (path, options) => {
|
|
|
4510
4487
|
return await createRustBom(path, options);
|
|
4511
4488
|
case "php":
|
|
4512
4489
|
options.multiProject = true;
|
|
4513
|
-
return
|
|
4490
|
+
return createPHPBom(path, options);
|
|
4514
4491
|
case "ruby":
|
|
4515
4492
|
options.multiProject = true;
|
|
4516
4493
|
return await createRubyBom(path, options);
|
|
@@ -4545,7 +4522,7 @@ export const createBom = async (path, options) => {
|
|
|
4545
4522
|
case "clj":
|
|
4546
4523
|
case "leiningen":
|
|
4547
4524
|
options.multiProject = true;
|
|
4548
|
-
return
|
|
4525
|
+
return createClojureBom(path, options);
|
|
4549
4526
|
case "github":
|
|
4550
4527
|
case "actions":
|
|
4551
4528
|
options.multiProject = true;
|
|
@@ -4587,7 +4564,7 @@ export const createBom = async (path, options) => {
|
|
|
4587
4564
|
return await createCloudBuildBom(path, options);
|
|
4588
4565
|
case "swift":
|
|
4589
4566
|
options.multiProject = true;
|
|
4590
|
-
return
|
|
4567
|
+
return createSwiftBom(path, options);
|
|
4591
4568
|
default:
|
|
4592
4569
|
// In recurse mode return multi-language Bom
|
|
4593
4570
|
// https://github.com/cyclonedx/cdxgen/issues/95
|
|
@@ -4606,7 +4583,7 @@ export const createBom = async (path, options) => {
|
|
|
4606
4583
|
* @param bomContents BOM Json
|
|
4607
4584
|
*/
|
|
4608
4585
|
export async function submitBom(args, bomContents) {
|
|
4609
|
-
|
|
4586
|
+
const serverUrl = args.serverUrl.replace(/\/$/, "") + "/api/v1/bom";
|
|
4610
4587
|
let encodedBomContents = Buffer.from(JSON.stringify(bomContents)).toString(
|
|
4611
4588
|
"base64"
|
|
4612
4589
|
);
|
|
@@ -4681,3 +4658,38 @@ export async function submitBom(args, bomContents) {
|
|
|
4681
4658
|
}
|
|
4682
4659
|
}
|
|
4683
4660
|
}
|
|
4661
|
+
|
|
4662
|
+
/**
|
|
4663
|
+
* Validate the generated bom using jsonschema
|
|
4664
|
+
*
|
|
4665
|
+
* @param {object} bomJson content
|
|
4666
|
+
*/
|
|
4667
|
+
export const validateBom = (bomJson) => {
|
|
4668
|
+
if (!bomJson) {
|
|
4669
|
+
return true;
|
|
4670
|
+
}
|
|
4671
|
+
const schema = JSON.parse(
|
|
4672
|
+
readFileSync(join(dirName, "data", "bom-1.5.schema.json"))
|
|
4673
|
+
);
|
|
4674
|
+
const defsSchema = JSON.parse(
|
|
4675
|
+
readFileSync(join(dirName, "data", "jsf-0.82.schema.json"))
|
|
4676
|
+
);
|
|
4677
|
+
const spdxSchema = JSON.parse(
|
|
4678
|
+
readFileSync(join(dirName, "data", "spdx.schema.json"))
|
|
4679
|
+
);
|
|
4680
|
+
const ajv = new Ajv({
|
|
4681
|
+
schemas: [schema, defsSchema, spdxSchema],
|
|
4682
|
+
strict: false,
|
|
4683
|
+
logger: false
|
|
4684
|
+
});
|
|
4685
|
+
addFormats(ajv);
|
|
4686
|
+
const validate = ajv.getSchema(
|
|
4687
|
+
"http://cyclonedx.org/schema/bom-1.5.schema.json"
|
|
4688
|
+
);
|
|
4689
|
+
const isValid = validate(bomJson);
|
|
4690
|
+
if (!isValid) {
|
|
4691
|
+
console.log(validate.errors);
|
|
4692
|
+
return false;
|
|
4693
|
+
}
|
|
4694
|
+
return true;
|
|
4695
|
+
};
|