@cyclonedx/cdxgen 11.2.2 → 11.2.4
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 +3 -1
- package/bin/cdxgen.js +40 -13
- package/bin/evinse.js +5 -1
- package/bin/verify.js +0 -4
- package/index.cjs +15 -0
- package/lib/cli/index.js +215 -24
- package/lib/evinser/evinser.js +167 -38
- package/lib/evinser/scalasem.js +52 -0
- package/lib/helpers/envcontext.js +1 -0
- package/lib/helpers/utils.js +217 -19
- package/lib/helpers/utils.test.js +49 -3
- package/lib/helpers/validator.js +1 -4
- package/lib/managers/binary.js +87 -84
- package/lib/server/server.js +13 -10
- package/package.json +25 -18
- package/types/lib/cli/index.d.ts +2 -3
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/evinser/scalasem.d.ts +6 -0
- package/types/lib/evinser/scalasem.d.ts.map +1 -0
- package/types/lib/helpers/envcontext.d.ts +1 -0
- package/types/lib/helpers/envcontext.d.ts.map +1 -1
- package/types/lib/helpers/utils.d.ts +27 -1
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/helpers/validator.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +0 -1
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/server/server.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -147,7 +147,8 @@ Options:
|
|
|
147
147
|
--server-host Listen address [default: "127.0.0.1"]
|
|
148
148
|
--server-port Listen port [default: "9090"]
|
|
149
149
|
--install-deps Install dependencies automatically for some projects. Defaults to true but disabled for c
|
|
150
|
-
ontainers and oci scans. Use --no-install-deps to disable this feature.
|
|
150
|
+
ontainers and oci scans. Use --no-install-deps to disable this feature.
|
|
151
|
+
[boolean] [default: true]
|
|
151
152
|
--validate Validate the generated SBOM using json schema. Defaults to true. Pass --no-validate to di
|
|
152
153
|
sable. [boolean] [default: true]
|
|
153
154
|
--evidence Generate SBOM with evidence for supported languages. [boolean] [default: false]
|
|
@@ -170,6 +171,7 @@ Options:
|
|
|
170
171
|
luated against or attested to.
|
|
171
172
|
[array] [choices: "asvs-5.0", "asvs-4.0.3", "bsimm-v13", "masvs-2.0.0", "nist_ssdf-1.1", "pcissc-secure-slc-1.1", "scv
|
|
172
173
|
s-1.0.0", "ssaf-DRAFT-2023-11"]
|
|
174
|
+
--json-pretty Pretty-print the generated BOM json. [boolean] [default: false]
|
|
173
175
|
--min-confidence Minimum confidence needed for the identity of a component from 0 - 1, where 1 is 100% con
|
|
174
176
|
fidence. [number] [default: 0]
|
|
175
177
|
--technique Analysis technique to use
|
package/bin/cdxgen.js
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
import { thoughtEnd, thoughtLog } from "../lib/helpers/logger.js";
|
|
25
25
|
import {
|
|
26
26
|
ATOM_DB,
|
|
27
|
+
DEBUG_MODE,
|
|
27
28
|
dirNameStr,
|
|
28
29
|
getTmpDir,
|
|
29
30
|
isMac,
|
|
@@ -55,10 +56,6 @@ if (configPath) {
|
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
let url = import.meta.url;
|
|
59
|
-
if (!url.startsWith("file://")) {
|
|
60
|
-
url = new URL(`file://${import.meta.url}`).toString();
|
|
61
|
-
}
|
|
62
59
|
const dirName = dirNameStr;
|
|
63
60
|
|
|
64
61
|
import yargs from "yargs";
|
|
@@ -221,6 +218,7 @@ const args = yargs(hideBin(process.argv))
|
|
|
221
218
|
description: "CycloneDX Specification version to use. Defaults to 1.6",
|
|
222
219
|
default: 1.6,
|
|
223
220
|
type: "number",
|
|
221
|
+
choices: [1.4, 1.5, 1.6],
|
|
224
222
|
})
|
|
225
223
|
.option("filter", {
|
|
226
224
|
description:
|
|
@@ -303,6 +301,11 @@ const args = yargs(hideBin(process.argv))
|
|
|
303
301
|
description:
|
|
304
302
|
"Do not show the donation banner. Set this attribute if you are an active sponsor for OWASP CycloneDX.",
|
|
305
303
|
})
|
|
304
|
+
.option("json-pretty", {
|
|
305
|
+
type: "boolean",
|
|
306
|
+
default: DEBUG_MODE,
|
|
307
|
+
description: "Pretty-print the generated BOM json.",
|
|
308
|
+
})
|
|
306
309
|
.option("feature-flags", {
|
|
307
310
|
description: "Experimental feature flags to enable. Advanced users only.",
|
|
308
311
|
hidden: true,
|
|
@@ -442,11 +445,23 @@ if (!options.projectType) {
|
|
|
442
445
|
"Ok, the user wants me to identify all the project types and generate a consolidated BOM document.",
|
|
443
446
|
);
|
|
444
447
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
448
|
+
// Handle dedicated cbom and saasbom commands
|
|
449
|
+
if (["cbom", "saasbom"].includes(process.argv[1])) {
|
|
450
|
+
if (process.argv[1].includes("cbom")) {
|
|
451
|
+
thoughtLog(
|
|
452
|
+
"Ok, the user wants to generate Cryptographic Bill-of-Materials (CBOM).",
|
|
453
|
+
);
|
|
454
|
+
options.includeCrypto = true;
|
|
455
|
+
} else if (process.argv[1].includes("saasbom")) {
|
|
456
|
+
thoughtLog(
|
|
457
|
+
"Ok, the user wants to generate a Software as a Service Bill-of-Materials (SaaSBOM). I should carefully collect the services, endpoints, and data flows.",
|
|
458
|
+
);
|
|
459
|
+
if (process.env?.CDXGEN_IN_CONTAINER !== "true") {
|
|
460
|
+
thoughtLog(
|
|
461
|
+
"Wait, I'm not running in a container. This means the chances of successfully collecting this inventory are quite low. Perhaps this is an advanced user who has set up atom and atom-tools already 🤔?",
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
450
465
|
options.evidence = true;
|
|
451
466
|
options.specVersion = 1.6;
|
|
452
467
|
options.deep = true;
|
|
@@ -693,7 +708,7 @@ const checkPermissions = (filePath, options) => {
|
|
|
693
708
|
"usages-slices-file",
|
|
694
709
|
"reachables-slices-file",
|
|
695
710
|
];
|
|
696
|
-
if (options?.type?.includes("swift")) {
|
|
711
|
+
if (options?.type?.includes("swift") || options?.type?.includes("scala")) {
|
|
697
712
|
slicesFilesKeys.push("semantics-slices-file");
|
|
698
713
|
}
|
|
699
714
|
for (const sf of slicesFilesKeys) {
|
|
@@ -798,7 +813,11 @@ const checkPermissions = (filePath, options) => {
|
|
|
798
813
|
fs.writeFileSync(jsonFile, bomNSData.bomJson);
|
|
799
814
|
jsonPayload = bomNSData.bomJson;
|
|
800
815
|
} else {
|
|
801
|
-
jsonPayload = JSON.stringify(
|
|
816
|
+
jsonPayload = JSON.stringify(
|
|
817
|
+
bomNSData.bomJson,
|
|
818
|
+
null,
|
|
819
|
+
options.jsonPretty ? 2 : null,
|
|
820
|
+
);
|
|
802
821
|
fs.writeFileSync(jsonFile, jsonPayload);
|
|
803
822
|
if (jsonFile.endsWith("bom.json")) {
|
|
804
823
|
thoughtLog(
|
|
@@ -900,7 +919,11 @@ const checkPermissions = (filePath, options) => {
|
|
|
900
919
|
bomJsonUnsignedObj.signature = signatureBlock;
|
|
901
920
|
fs.writeFileSync(
|
|
902
921
|
jsonFile,
|
|
903
|
-
JSON.stringify(
|
|
922
|
+
JSON.stringify(
|
|
923
|
+
bomJsonUnsignedObj,
|
|
924
|
+
null,
|
|
925
|
+
options.jsonPretty ? 2 : null,
|
|
926
|
+
),
|
|
904
927
|
);
|
|
905
928
|
thoughtLog(`Signing the BOM file "${jsonFile}".`);
|
|
906
929
|
if (publicKeyFile) {
|
|
@@ -937,7 +960,9 @@ const checkPermissions = (filePath, options) => {
|
|
|
937
960
|
}
|
|
938
961
|
} else if (!options.print) {
|
|
939
962
|
if (bomNSData.bomJson) {
|
|
940
|
-
console.log(
|
|
963
|
+
console.log(
|
|
964
|
+
JSON.stringify(bomNSData.bomJson, null, options.jsonPretty ? 2 : null),
|
|
965
|
+
);
|
|
941
966
|
} else {
|
|
942
967
|
console.log("Unable to produce BOM for", filePath);
|
|
943
968
|
console.log("Try running the command with -t <type> or -r argument");
|
|
@@ -967,6 +992,7 @@ const checkPermissions = (filePath, options) => {
|
|
|
967
992
|
includeCrypto: options.includeCrypto,
|
|
968
993
|
specVersion: options.specVersion,
|
|
969
994
|
profile: options.profile,
|
|
995
|
+
jsonPretty: options.jsonPretty,
|
|
970
996
|
};
|
|
971
997
|
const dbObjMap = await evinserModule.prepareDB(evinseOptions);
|
|
972
998
|
if (dbObjMap) {
|
|
@@ -1003,6 +1029,7 @@ const checkPermissions = (filePath, options) => {
|
|
|
1003
1029
|
await submitBom(options, bomNSData.bomJson);
|
|
1004
1030
|
} catch (err) {
|
|
1005
1031
|
console.log(err);
|
|
1032
|
+
process.exit(1);
|
|
1006
1033
|
}
|
|
1007
1034
|
}
|
|
1008
1035
|
// Protobuf serialization
|
package/bin/evinse.js
CHANGED
|
@@ -73,6 +73,7 @@ const args = yargs(hideBin(process.argv))
|
|
|
73
73
|
"swift",
|
|
74
74
|
"ios",
|
|
75
75
|
"ruby",
|
|
76
|
+
"scala",
|
|
76
77
|
],
|
|
77
78
|
})
|
|
78
79
|
.option("db-path", {
|
|
@@ -127,7 +128,10 @@ const args = yargs(hideBin(process.argv))
|
|
|
127
128
|
.option("semantics-slices-file", {
|
|
128
129
|
description: "Use an existing semantics slices file.",
|
|
129
130
|
default: "semantics.slices.json",
|
|
130
|
-
|
|
131
|
+
})
|
|
132
|
+
.option("openapi-spec-file", {
|
|
133
|
+
description: "Use an existing openapi specification file (SaaSBOM).",
|
|
134
|
+
default: "openapi.json",
|
|
131
135
|
})
|
|
132
136
|
.option("print", {
|
|
133
137
|
alias: "p",
|
package/bin/verify.js
CHANGED
|
@@ -9,10 +9,6 @@ import yargs from "yargs";
|
|
|
9
9
|
import { hideBin } from "yargs/helpers";
|
|
10
10
|
import { dirNameStr } from "../lib/helpers/utils.js";
|
|
11
11
|
|
|
12
|
-
let url = import.meta.url;
|
|
13
|
-
if (!url.startsWith("file://")) {
|
|
14
|
-
url = new URL(`file://${import.meta.url}`).toString();
|
|
15
|
-
}
|
|
16
12
|
const dirName = dirNameStr;
|
|
17
13
|
|
|
18
14
|
const args = yargs(hideBin(process.argv))
|
package/index.cjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// this file is a wrapper of ./lib/cli/index.js that can be used by commonjs projects importing this module
|
|
2
|
+
// that prefer to use require instead of await import()
|
|
3
|
+
const importPromise = import("./lib/cli/index.js");
|
|
4
|
+
|
|
5
|
+
module.exports = new Proxy(
|
|
6
|
+
{},
|
|
7
|
+
{
|
|
8
|
+
get:
|
|
9
|
+
(_, prop) =>
|
|
10
|
+
async (...args) => {
|
|
11
|
+
const mod = await importPromise;
|
|
12
|
+
return typeof mod[prop] === "function" ? mod[prop](...args) : mod[prop];
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
);
|
package/lib/cli/index.js
CHANGED
|
@@ -73,6 +73,7 @@ import {
|
|
|
73
73
|
getGradleCommand,
|
|
74
74
|
getLicenses,
|
|
75
75
|
getMavenCommand,
|
|
76
|
+
getMillCommand,
|
|
76
77
|
getMvnMetadata,
|
|
77
78
|
getNugetMetadata,
|
|
78
79
|
getPipFrozenTree,
|
|
@@ -130,6 +131,7 @@ import {
|
|
|
130
131
|
parseLeiningenData,
|
|
131
132
|
parseMakeDFile,
|
|
132
133
|
parseMavenTree,
|
|
134
|
+
parseMillDependency,
|
|
133
135
|
parseMinJs,
|
|
134
136
|
parseMixLockData,
|
|
135
137
|
parseNodeShrinkwrap,
|
|
@@ -180,10 +182,6 @@ import {
|
|
|
180
182
|
parseImageName,
|
|
181
183
|
} from "../managers/docker.js";
|
|
182
184
|
|
|
183
|
-
let url = import.meta.url;
|
|
184
|
-
if (!url.startsWith("file://")) {
|
|
185
|
-
url = new URL(`file://${import.meta.url}`).toString();
|
|
186
|
-
}
|
|
187
185
|
const dirName = dirNameStr;
|
|
188
186
|
|
|
189
187
|
const selfPJson = JSON.parse(
|
|
@@ -416,7 +414,10 @@ const addLifecyclesSection = (options) => {
|
|
|
416
414
|
if (inspectData) {
|
|
417
415
|
lifecycles.push({ phase: "post-build" });
|
|
418
416
|
}
|
|
419
|
-
} else if (
|
|
417
|
+
} else if (
|
|
418
|
+
options?.projectType?.length &&
|
|
419
|
+
options?.projectType?.includes("binary")
|
|
420
|
+
) {
|
|
420
421
|
lifecycles.push({ phase: "post-build" });
|
|
421
422
|
}
|
|
422
423
|
if (options.projectType?.includes("os")) {
|
|
@@ -1393,8 +1394,8 @@ export async function createJarBom(path, options) {
|
|
|
1393
1394
|
if (hpiFiles.length) {
|
|
1394
1395
|
jarFiles = jarFiles.concat(hpiFiles);
|
|
1395
1396
|
}
|
|
1396
|
-
const tempDir = mkdtempSync(join(getTmpDir(), "jar-deps-"));
|
|
1397
1397
|
for (const jar of jarFiles) {
|
|
1398
|
+
const tempDir = mkdtempSync(join(getTmpDir(), "jar-deps-"));
|
|
1398
1399
|
if (DEBUG_MODE) {
|
|
1399
1400
|
console.log(`Parsing ${jar}`);
|
|
1400
1401
|
}
|
|
@@ -1405,10 +1406,10 @@ export async function createJarBom(path, options) {
|
|
|
1405
1406
|
if (pkgList.length) {
|
|
1406
1407
|
pkgList = await getMvnMetadata(pkgList);
|
|
1407
1408
|
}
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1409
|
+
// Clean up
|
|
1410
|
+
if (tempDir?.startsWith(getTmpDir()) && rmSync) {
|
|
1411
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
1412
|
+
}
|
|
1412
1413
|
}
|
|
1413
1414
|
pkgList = pkgList.concat(convertJarNSToPackages(nsMapping));
|
|
1414
1415
|
return buildBomNSData(options, pkgList, "maven", {
|
|
@@ -1513,10 +1514,20 @@ export async function createJavaBom(path, options) {
|
|
|
1513
1514
|
`${options.multiProject ? "**/" : ""}build.gradle*`,
|
|
1514
1515
|
options,
|
|
1515
1516
|
);
|
|
1517
|
+
// mill
|
|
1518
|
+
const millFiles = getAllFiles(
|
|
1519
|
+
path,
|
|
1520
|
+
`${options.multiProject ? "**/" : ""}build.mill`,
|
|
1521
|
+
options,
|
|
1522
|
+
);
|
|
1516
1523
|
let bomJsonFiles = [];
|
|
1517
1524
|
if (
|
|
1518
1525
|
pomFiles?.length &&
|
|
1519
|
-
isPackageManagerAllowed(
|
|
1526
|
+
isPackageManagerAllowed(
|
|
1527
|
+
"maven",
|
|
1528
|
+
["bazel", "sbt", "gradle", "mill"],
|
|
1529
|
+
options,
|
|
1530
|
+
)
|
|
1520
1531
|
) {
|
|
1521
1532
|
if (gradleFiles.length) {
|
|
1522
1533
|
thoughtLog(
|
|
@@ -1542,7 +1553,7 @@ export async function createJavaBom(path, options) {
|
|
|
1542
1553
|
let mvnArgs;
|
|
1543
1554
|
if (isQuarkus) {
|
|
1544
1555
|
thoughtLog(
|
|
1545
|
-
"This appears to be a
|
|
1556
|
+
"This appears to be a Quarkus project. Let's use the right Maven plugin.",
|
|
1546
1557
|
);
|
|
1547
1558
|
// disable analytics. See: https://quarkus.io/usage/
|
|
1548
1559
|
mvnArgs = [
|
|
@@ -1550,6 +1561,11 @@ export async function createJavaBom(path, options) {
|
|
|
1550
1561
|
"quarkus:dependency-sbom",
|
|
1551
1562
|
"-Dquarkus.analytics.disabled=true",
|
|
1552
1563
|
];
|
|
1564
|
+
if (options.specVersion) {
|
|
1565
|
+
mvnArgs = mvnArgs.concat(
|
|
1566
|
+
`-Dquarkus.dependency.sbom.schema-version=${options.specVersion}`,
|
|
1567
|
+
);
|
|
1568
|
+
}
|
|
1553
1569
|
} else {
|
|
1554
1570
|
const cdxMavenPlugin =
|
|
1555
1571
|
process.env.CDX_MAVEN_PLUGIN ||
|
|
@@ -1755,7 +1771,7 @@ export async function createJavaBom(path, options) {
|
|
|
1755
1771
|
);
|
|
1756
1772
|
} else {
|
|
1757
1773
|
console.log(
|
|
1758
|
-
"1. Java version requirement: cdxgen container image bundles Java
|
|
1774
|
+
"1. Java version requirement: cdxgen container image bundles Java 24 with maven 3.9 which might be incompatible. Try running cdxgen with the custom JDK11-based image `ghcr.io/cyclonedx/cdxgen-java11:v11`.",
|
|
1759
1775
|
);
|
|
1760
1776
|
}
|
|
1761
1777
|
console.log(
|
|
@@ -1937,7 +1953,11 @@ export async function createJavaBom(path, options) {
|
|
|
1937
1953
|
// Execute gradle properties
|
|
1938
1954
|
if (
|
|
1939
1955
|
gradleFiles?.length &&
|
|
1940
|
-
isPackageManagerAllowed(
|
|
1956
|
+
isPackageManagerAllowed(
|
|
1957
|
+
"gradle",
|
|
1958
|
+
["maven", "bazel", "sbt", "mill"],
|
|
1959
|
+
options,
|
|
1960
|
+
)
|
|
1941
1961
|
) {
|
|
1942
1962
|
let rootProjects = [null];
|
|
1943
1963
|
let allProjectsStr = [];
|
|
@@ -2073,7 +2093,11 @@ export async function createJavaBom(path, options) {
|
|
|
2073
2093
|
if (
|
|
2074
2094
|
gradleFiles?.length &&
|
|
2075
2095
|
options.installDeps &&
|
|
2076
|
-
isPackageManagerAllowed(
|
|
2096
|
+
isPackageManagerAllowed(
|
|
2097
|
+
"gradle",
|
|
2098
|
+
["maven", "bazel", "sbt", "mill"],
|
|
2099
|
+
options,
|
|
2100
|
+
)
|
|
2077
2101
|
) {
|
|
2078
2102
|
allProjects.push(parentComponent);
|
|
2079
2103
|
const gradleCmd = getGradleCommand(gradleRootPath, null);
|
|
@@ -2209,7 +2233,11 @@ export async function createJavaBom(path, options) {
|
|
|
2209
2233
|
if (
|
|
2210
2234
|
bazelFiles?.length &&
|
|
2211
2235
|
!hasAnyProjectType(["docker", "oci", "container", "os"], options, false) &&
|
|
2212
|
-
isPackageManagerAllowed(
|
|
2236
|
+
isPackageManagerAllowed(
|
|
2237
|
+
"bazel",
|
|
2238
|
+
["maven", "gradle", "sbt", "mill"],
|
|
2239
|
+
options,
|
|
2240
|
+
)
|
|
2213
2241
|
) {
|
|
2214
2242
|
let BAZEL_CMD = "bazel";
|
|
2215
2243
|
if (process.env.BAZEL_HOME) {
|
|
@@ -2347,10 +2375,15 @@ export async function createJavaBom(path, options) {
|
|
|
2347
2375
|
`${options.multiProject ? "**/" : ""}build.sbt.lock`,
|
|
2348
2376
|
options,
|
|
2349
2377
|
);
|
|
2350
|
-
|
|
2378
|
+
const tempCacheDir = mkdtempSync(join(getTmpDir(), "sbt-cache-"));
|
|
2379
|
+
safeMkdirSync(tempCacheDir, { recursive: true });
|
|
2351
2380
|
if (
|
|
2352
2381
|
sbtProjects?.length &&
|
|
2353
|
-
isPackageManagerAllowed(
|
|
2382
|
+
isPackageManagerAllowed(
|
|
2383
|
+
"sbt",
|
|
2384
|
+
["bazel", "maven", "gradle", "mill"],
|
|
2385
|
+
options,
|
|
2386
|
+
)
|
|
2354
2387
|
) {
|
|
2355
2388
|
// If the project use sbt lock files
|
|
2356
2389
|
if (sbtLockFiles?.length) {
|
|
@@ -2402,6 +2435,14 @@ export async function createJavaBom(path, options) {
|
|
|
2402
2435
|
}
|
|
2403
2436
|
}
|
|
2404
2437
|
writeFileSync(tempSbtPlugins, sbtPluginDefinition);
|
|
2438
|
+
let sbtExtraArgs = "";
|
|
2439
|
+
const env = { ...process.env };
|
|
2440
|
+
// We need to collect the jars from the cache
|
|
2441
|
+
if (options.deep) {
|
|
2442
|
+
sbtExtraArgs = " updateClassifiers";
|
|
2443
|
+
env["COURSIER_CACHE"] = tempCacheDir;
|
|
2444
|
+
env["SBT_IVY_HOME"] = tempCacheDir;
|
|
2445
|
+
}
|
|
2405
2446
|
for (const i in sbtProjects) {
|
|
2406
2447
|
const basePath = sbtProjects[i];
|
|
2407
2448
|
const dlFile = join(tempDir, `dl-${i}.tmp`);
|
|
@@ -2416,11 +2457,11 @@ export async function createJavaBom(path, options) {
|
|
|
2416
2457
|
// write to the existing plugins file
|
|
2417
2458
|
if (useSlashSyntax) {
|
|
2418
2459
|
sbtArgs = [
|
|
2419
|
-
`'set ThisBuild / asciiGraphWidth :=
|
|
2460
|
+
`'set ThisBuild / asciiGraphWidth := 800'${sbtExtraArgs} "dependencyTree / toFile ${dlFile} --force"`,
|
|
2420
2461
|
];
|
|
2421
2462
|
} else {
|
|
2422
2463
|
sbtArgs = [
|
|
2423
|
-
`'set asciiGraphWidth in ThisBuild :=
|
|
2464
|
+
`'set asciiGraphWidth in ThisBuild := 800'${sbtExtraArgs} "dependencyTree::toFile ${dlFile} --force"`,
|
|
2424
2465
|
];
|
|
2425
2466
|
}
|
|
2426
2467
|
pluginFile = addPlugin(basePath, sbtPluginDefinition);
|
|
@@ -2441,6 +2482,7 @@ export async function createJavaBom(path, options) {
|
|
|
2441
2482
|
encoding: "utf-8",
|
|
2442
2483
|
timeout: TIMEOUT_MS,
|
|
2443
2484
|
maxBuffer: MAX_BUFFER,
|
|
2485
|
+
env,
|
|
2444
2486
|
});
|
|
2445
2487
|
if (result.status !== 0 || result.error) {
|
|
2446
2488
|
console.error(result.stdout, result.stderr);
|
|
@@ -2492,12 +2534,148 @@ export async function createJavaBom(path, options) {
|
|
|
2492
2534
|
}
|
|
2493
2535
|
// Should we attempt to resolve class names
|
|
2494
2536
|
if (options.resolveClass || options.deep) {
|
|
2495
|
-
const tmpjarNSMapping = await collectJarNS(
|
|
2537
|
+
const tmpjarNSMapping = await collectJarNS(tempCacheDir);
|
|
2496
2538
|
if (tmpjarNSMapping && Object.keys(tmpjarNSMapping).length) {
|
|
2497
2539
|
jarNSMapping = { ...jarNSMapping, ...tmpjarNSMapping };
|
|
2498
2540
|
}
|
|
2541
|
+
// sbt can store jars in the target directory
|
|
2542
|
+
const jarNSData = await createJarBom(path, options);
|
|
2543
|
+
if (jarNSData?.bomJson?.components) {
|
|
2544
|
+
pkgList = pkgList.concat(jarNSData?.bomJson?.components);
|
|
2545
|
+
const targetJarNSMapping = {};
|
|
2546
|
+
for (const p of jarNSData.bomJson.components) {
|
|
2547
|
+
if (!p?.purl || !p?.properties?.length) {
|
|
2548
|
+
continue;
|
|
2549
|
+
}
|
|
2550
|
+
const nsProp = p.properties.filter(
|
|
2551
|
+
(prop) => prop.name === "Namespaces",
|
|
2552
|
+
);
|
|
2553
|
+
if (nsProp.length) {
|
|
2554
|
+
targetJarNSMapping[p.purl] = nsProp[0].value;
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
jarNSMapping = { ...jarNSMapping, ...targetJarNSMapping };
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
if (tempCacheDir?.startsWith(getTmpDir())) {
|
|
2562
|
+
rmSync(tempCacheDir, {
|
|
2563
|
+
recursive: true,
|
|
2564
|
+
force: true,
|
|
2565
|
+
});
|
|
2566
|
+
}
|
|
2567
|
+
|
|
2568
|
+
if (
|
|
2569
|
+
millFiles?.length &&
|
|
2570
|
+
isPackageManagerAllowed(
|
|
2571
|
+
"mill",
|
|
2572
|
+
["bazel", "sbt", "gradle", "maven"],
|
|
2573
|
+
options,
|
|
2574
|
+
)
|
|
2575
|
+
) {
|
|
2576
|
+
const millRootPath = dirname(millFiles[0]);
|
|
2577
|
+
parentComponent = createDefaultParentComponent(
|
|
2578
|
+
millRootPath,
|
|
2579
|
+
"maven",
|
|
2580
|
+
options,
|
|
2581
|
+
);
|
|
2582
|
+
const millCmd = getMillCommand(millRootPath);
|
|
2583
|
+
const millCommonArgs = [
|
|
2584
|
+
"--no-server",
|
|
2585
|
+
"--silent",
|
|
2586
|
+
"--disable-prompt",
|
|
2587
|
+
"--disable-callgraph",
|
|
2588
|
+
"-k",
|
|
2589
|
+
"--color",
|
|
2590
|
+
"false",
|
|
2591
|
+
];
|
|
2592
|
+
const millArgs = [...millCommonArgs, "__.ivyDepsTree"];
|
|
2593
|
+
if (DEBUG_MODE) {
|
|
2594
|
+
console.log("Executing", millCmd, millArgs.join(" "), "in", millRootPath);
|
|
2595
|
+
}
|
|
2596
|
+
let sresult = spawnSync(millCmd, millArgs, {
|
|
2597
|
+
cwd: millRootPath,
|
|
2598
|
+
encoding: "utf-8",
|
|
2599
|
+
shell: isWin,
|
|
2600
|
+
timeout: TIMEOUT_MS,
|
|
2601
|
+
maxBuffer: MAX_BUFFER * 10,
|
|
2602
|
+
});
|
|
2603
|
+
if (sresult.status !== 0 || sresult.error) {
|
|
2604
|
+
if (options.failOnError || DEBUG_MODE) {
|
|
2605
|
+
console.error(sresult.stdout, sresult.stderr);
|
|
2606
|
+
}
|
|
2607
|
+
options.failOnError && process.exit(1);
|
|
2608
|
+
}
|
|
2609
|
+
const millResolveArgs = [...millCommonArgs, "resolve", "__.ivyDepsTree"];
|
|
2610
|
+
if (DEBUG_MODE) {
|
|
2611
|
+
console.log(
|
|
2612
|
+
"Executing",
|
|
2613
|
+
millCmd,
|
|
2614
|
+
millResolveArgs.join(" "),
|
|
2615
|
+
"in",
|
|
2616
|
+
millRootPath,
|
|
2617
|
+
);
|
|
2618
|
+
}
|
|
2619
|
+
sresult = spawnSync(millCmd, millResolveArgs, {
|
|
2620
|
+
cwd: millRootPath,
|
|
2621
|
+
encoding: "utf-8",
|
|
2622
|
+
shell: isWin,
|
|
2623
|
+
timeout: TIMEOUT_MS,
|
|
2624
|
+
maxBuffer: MAX_BUFFER,
|
|
2625
|
+
});
|
|
2626
|
+
if (sresult.status !== 0 || sresult.error) {
|
|
2627
|
+
if (options.failOnError || DEBUG_MODE) {
|
|
2628
|
+
console.error(sresult.stdout, sresult.stderr);
|
|
2629
|
+
}
|
|
2630
|
+
options.failOnError && process.exit(1);
|
|
2631
|
+
}
|
|
2632
|
+
const sstdout = sresult.stdout;
|
|
2633
|
+
if (sstdout) {
|
|
2634
|
+
parentComponent.components = [];
|
|
2635
|
+
const modules = sstdout
|
|
2636
|
+
.trim()
|
|
2637
|
+
.split("\n")
|
|
2638
|
+
.map((a) => a.substring(0, a.lastIndexOf(".")))
|
|
2639
|
+
.filter((a) =>
|
|
2640
|
+
["true", "1"].includes(process.env.MILL_EXCLUDE_TEST)
|
|
2641
|
+
? !a.endsWith(".test")
|
|
2642
|
+
: true,
|
|
2643
|
+
);
|
|
2644
|
+
const moduleBomRefs = [];
|
|
2645
|
+
const packages = new Map();
|
|
2646
|
+
const relations = new Map();
|
|
2647
|
+
relations.set(parentComponent["bom-ref"], []);
|
|
2648
|
+
for (const module of modules) {
|
|
2649
|
+
moduleBomRefs.push(
|
|
2650
|
+
parseMillDependency(module, packages, relations, millRootPath),
|
|
2651
|
+
);
|
|
2652
|
+
}
|
|
2653
|
+
for (const module of moduleBomRefs) {
|
|
2654
|
+
parentComponent.components.push(packages.get(module));
|
|
2655
|
+
relations.get(parentComponent["bom-ref"]).push(module);
|
|
2656
|
+
packages.delete(module);
|
|
2657
|
+
}
|
|
2658
|
+
const newDependencies = [];
|
|
2659
|
+
for (const [ref, dependsOn] of relations.entries()) {
|
|
2660
|
+
newDependencies.push({
|
|
2661
|
+
ref,
|
|
2662
|
+
dependsOn,
|
|
2663
|
+
});
|
|
2664
|
+
}
|
|
2665
|
+
if (DEBUG_MODE) {
|
|
2666
|
+
console.log(
|
|
2667
|
+
`Obtained ${packages.size} components and ${relations.size} dependencies from mill.`,
|
|
2668
|
+
);
|
|
2669
|
+
}
|
|
2670
|
+
pkgList = pkgList.concat(...packages.values());
|
|
2671
|
+
dependencies = mergeDependencies(
|
|
2672
|
+
dependencies,
|
|
2673
|
+
newDependencies,
|
|
2674
|
+
parentComponent,
|
|
2675
|
+
);
|
|
2499
2676
|
}
|
|
2500
2677
|
}
|
|
2678
|
+
|
|
2501
2679
|
pkgList = trimComponents(pkgList);
|
|
2502
2680
|
pkgList = await getMvnMetadata(pkgList, jarNSMapping, options.deep);
|
|
2503
2681
|
return buildBomNSData(options, pkgList, "maven", {
|
|
@@ -6669,6 +6847,16 @@ export function dedupeBom(options, components, parentComponent, dependencies) {
|
|
|
6669
6847
|
dependencies = [];
|
|
6670
6848
|
}
|
|
6671
6849
|
components = trimComponents(components);
|
|
6850
|
+
// Let's apply some common tweaks
|
|
6851
|
+
// Convert evidence.identity section to an object for 1.5
|
|
6852
|
+
if (options.specVersion === 1.5) {
|
|
6853
|
+
for (const comp of components) {
|
|
6854
|
+
if (comp?.evidence?.identity && Array.isArray(comp.evidence.identity)) {
|
|
6855
|
+
comp.evidence.identity = comp.evidence.identity[0];
|
|
6856
|
+
delete comp.evidence.identity.concludedValue;
|
|
6857
|
+
}
|
|
6858
|
+
}
|
|
6859
|
+
}
|
|
6672
6860
|
if (DEBUG_MODE) {
|
|
6673
6861
|
console.log(
|
|
6674
6862
|
`Obtained ${components.length} components and ${dependencies.length} dependencies after dedupe.`,
|
|
@@ -6723,7 +6911,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
6723
6911
|
binPaths,
|
|
6724
6912
|
executables,
|
|
6725
6913
|
sharedLibs,
|
|
6726
|
-
} = getOSPackages(
|
|
6914
|
+
} = await getOSPackages(
|
|
6727
6915
|
options.allLayersExplodedDir,
|
|
6728
6916
|
options.exportData?.inspectData?.Config,
|
|
6729
6917
|
);
|
|
@@ -8069,7 +8257,8 @@ export async function createBom(path, options) {
|
|
|
8069
8257
|
*
|
|
8070
8258
|
* @param {Object} args CLI args
|
|
8071
8259
|
* @param {Object} bomContents BOM Json
|
|
8072
|
-
* @return {Promise<{ token: string } |
|
|
8260
|
+
* @return {Promise<{ token: string } | undefined>} a promise with a token (if request was successful) or undefined (in case of invalid arguments)
|
|
8261
|
+
* @throws {Error} if the request fails
|
|
8073
8262
|
*/
|
|
8074
8263
|
export async function submitBom(args, bomContents) {
|
|
8075
8264
|
const serverUrl = `${args.serverUrl.replace(/\/$/, "")}/api/v1/bom`;
|
|
@@ -8102,6 +8291,7 @@ export async function submitBom(args, bomContents) {
|
|
|
8102
8291
|
console.log(
|
|
8103
8292
|
"projectId, projectName and projectVersion, or all three must be provided.",
|
|
8104
8293
|
);
|
|
8294
|
+
args.failOnError && process.exit(1);
|
|
8105
8295
|
return;
|
|
8106
8296
|
}
|
|
8107
8297
|
if (
|
|
@@ -8187,6 +8377,7 @@ export async function submitBom(args, bomContents) {
|
|
|
8187
8377
|
console.log("Unable to submit the SBOM to the Dependency-Track server");
|
|
8188
8378
|
}
|
|
8189
8379
|
}
|
|
8190
|
-
|
|
8380
|
+
// rethrow error as function is async and we should try to catch it in the caller
|
|
8381
|
+
throw error;
|
|
8191
8382
|
}
|
|
8192
8383
|
}
|