@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/utils.js
CHANGED
|
@@ -48,6 +48,7 @@ import { satisfies, coerce, maxSatisfying, clean, valid } from "semver";
|
|
|
48
48
|
import StreamZip from "node-stream-zip";
|
|
49
49
|
import { parseEDNString } from "edn-data";
|
|
50
50
|
import { PackageURL } from "packageurl-js";
|
|
51
|
+
import { getTreeWithPlugin } from "./piptree.js";
|
|
51
52
|
|
|
52
53
|
const selfPJson = JSON.parse(readFileSync(join(dirName, "package.json")));
|
|
53
54
|
const _version = selfPJson.version;
|
|
@@ -195,7 +196,7 @@ export function getLicenses(pkg, format = "xml") {
|
|
|
195
196
|
* the text to the license text object and stop.
|
|
196
197
|
*/
|
|
197
198
|
export function addLicenseText(pkg, l, licenseContent, format = "xml") {
|
|
198
|
-
|
|
199
|
+
const licenseFilenames = [
|
|
199
200
|
"LICENSE",
|
|
200
201
|
"License",
|
|
201
202
|
"license",
|
|
@@ -206,7 +207,7 @@ export function addLicenseText(pkg, l, licenseContent, format = "xml") {
|
|
|
206
207
|
"Notice",
|
|
207
208
|
"notice"
|
|
208
209
|
];
|
|
209
|
-
|
|
210
|
+
const licenseContentTypes = {
|
|
210
211
|
"text/plain": "",
|
|
211
212
|
"text/txt": ".txt",
|
|
212
213
|
"text/markdown": ".md",
|
|
@@ -219,7 +220,7 @@ export function addLicenseText(pkg, l, licenseContent, format = "xml") {
|
|
|
219
220
|
for (const [licenseContentType, fileExtension] of Object.entries(
|
|
220
221
|
licenseContentTypes
|
|
221
222
|
)) {
|
|
222
|
-
|
|
223
|
+
const licenseFilepath = `${pkg.realPath}/${licenseFilename}${licenseName}${fileExtension}`;
|
|
223
224
|
if (existsSync(licenseFilepath)) {
|
|
224
225
|
licenseContent.text = readLicenseText(
|
|
225
226
|
licenseFilepath,
|
|
@@ -242,16 +243,16 @@ export function readLicenseText(
|
|
|
242
243
|
licenseContentType,
|
|
243
244
|
format = "xml"
|
|
244
245
|
) {
|
|
245
|
-
|
|
246
|
+
const licenseText = readFileSync(licenseFilepath, "utf8");
|
|
246
247
|
if (licenseText) {
|
|
247
248
|
if (format === "xml") {
|
|
248
|
-
|
|
249
|
+
const licenseContentText = { "#cdata": licenseText };
|
|
249
250
|
if (licenseContentType !== "text/plain") {
|
|
250
251
|
licenseContentText["@content-type"] = licenseContentType;
|
|
251
252
|
}
|
|
252
253
|
return licenseContentText;
|
|
253
254
|
} else {
|
|
254
|
-
|
|
255
|
+
const licenseContentText = { content: licenseText };
|
|
255
256
|
if (licenseContentType !== "text/plain") {
|
|
256
257
|
licenseContentText["contentType"] = licenseContentType;
|
|
257
258
|
}
|
|
@@ -315,7 +316,7 @@ const _getDepPkgList = async function (
|
|
|
315
316
|
depKeys,
|
|
316
317
|
pkg
|
|
317
318
|
) {
|
|
318
|
-
|
|
319
|
+
const pkgDependencies =
|
|
319
320
|
pkg.lockfileVersion && pkg.lockfileVersion >= 3
|
|
320
321
|
? pkg.packages
|
|
321
322
|
: pkg.dependencies;
|
|
@@ -326,7 +327,7 @@ const _getDepPkgList = async function (
|
|
|
326
327
|
if (k === "") {
|
|
327
328
|
continue;
|
|
328
329
|
}
|
|
329
|
-
|
|
330
|
+
const name = k;
|
|
330
331
|
const version = pkgDependencies[name].version;
|
|
331
332
|
const purl = new PackageURL(
|
|
332
333
|
"npm",
|
|
@@ -337,7 +338,7 @@ const _getDepPkgList = async function (
|
|
|
337
338
|
null
|
|
338
339
|
);
|
|
339
340
|
const purlString = decodeURIComponent(purl.toString());
|
|
340
|
-
|
|
341
|
+
const scope = pkgDependencies[name].dev === true ? "optional" : undefined;
|
|
341
342
|
const apkg = {
|
|
342
343
|
name: name.replace("node_modules/", ""),
|
|
343
344
|
version,
|
|
@@ -348,7 +349,20 @@ const _getDepPkgList = async function (
|
|
|
348
349
|
name: "SrcFile",
|
|
349
350
|
value: pkgLockFile
|
|
350
351
|
}
|
|
351
|
-
]
|
|
352
|
+
],
|
|
353
|
+
evidence: {
|
|
354
|
+
identity: {
|
|
355
|
+
field: "purl",
|
|
356
|
+
confidence: 1,
|
|
357
|
+
methods: [
|
|
358
|
+
{
|
|
359
|
+
technique: "manifest-analysis",
|
|
360
|
+
confidence: 1,
|
|
361
|
+
value: pkgLockFile
|
|
362
|
+
}
|
|
363
|
+
]
|
|
364
|
+
}
|
|
365
|
+
}
|
|
352
366
|
};
|
|
353
367
|
pkgList.push(apkg);
|
|
354
368
|
if (pkgDependencies[name].dependencies) {
|
|
@@ -422,7 +436,20 @@ export const parsePkgJson = async (pkgJsonFile) => {
|
|
|
422
436
|
name: "SrcFile",
|
|
423
437
|
value: pkgJsonFile
|
|
424
438
|
}
|
|
425
|
-
]
|
|
439
|
+
],
|
|
440
|
+
evidence: {
|
|
441
|
+
identity: {
|
|
442
|
+
field: "purl",
|
|
443
|
+
confidence: 1,
|
|
444
|
+
methods: [
|
|
445
|
+
{
|
|
446
|
+
technique: "manifest-analysis",
|
|
447
|
+
confidence: 1,
|
|
448
|
+
value: pkgJsonFile
|
|
449
|
+
}
|
|
450
|
+
]
|
|
451
|
+
}
|
|
452
|
+
}
|
|
426
453
|
});
|
|
427
454
|
} catch (err) {
|
|
428
455
|
// continue regardless of error
|
|
@@ -446,8 +473,8 @@ export const parsePkgJson = async (pkgJsonFile) => {
|
|
|
446
473
|
*/
|
|
447
474
|
export const parsePkgLock = async (pkgLockFile) => {
|
|
448
475
|
let pkgList = [];
|
|
449
|
-
|
|
450
|
-
|
|
476
|
+
const dependenciesList = [];
|
|
477
|
+
const depKeys = {};
|
|
451
478
|
let rootPkg = {};
|
|
452
479
|
if (existsSync(pkgLockFile)) {
|
|
453
480
|
const lockData = JSON.parse(readFileSync(pkgLockFile, "utf8"));
|
|
@@ -652,7 +679,20 @@ export const parseYarnLock = async function (yarnLockFile) {
|
|
|
652
679
|
name: "SrcFile",
|
|
653
680
|
value: yarnLockFile
|
|
654
681
|
}
|
|
655
|
-
]
|
|
682
|
+
],
|
|
683
|
+
evidence: {
|
|
684
|
+
identity: {
|
|
685
|
+
field: "purl",
|
|
686
|
+
confidence: 1,
|
|
687
|
+
methods: [
|
|
688
|
+
{
|
|
689
|
+
technique: "manifest-analysis",
|
|
690
|
+
confidence: 1,
|
|
691
|
+
value: yarnLockFile
|
|
692
|
+
}
|
|
693
|
+
]
|
|
694
|
+
}
|
|
695
|
+
}
|
|
656
696
|
});
|
|
657
697
|
// Reset all the variables
|
|
658
698
|
group = "";
|
|
@@ -766,7 +806,7 @@ export const parseNodeShrinkwrap = async function (swFile) {
|
|
|
766
806
|
if (existsSync(swFile)) {
|
|
767
807
|
const lockData = JSON.parse(readFileSync(swFile, "utf8"));
|
|
768
808
|
const pkgKeys = Object.keys(lockData);
|
|
769
|
-
for (
|
|
809
|
+
for (const k in pkgKeys) {
|
|
770
810
|
const fullName = pkgKeys[k];
|
|
771
811
|
const integrity = lockData[fullName];
|
|
772
812
|
const parts = fullName.split("@");
|
|
@@ -779,7 +819,7 @@ export const parseNodeShrinkwrap = async function (swFile) {
|
|
|
779
819
|
version = parts[1];
|
|
780
820
|
} else if (parts.length === 3) {
|
|
781
821
|
if (parts[0] === "") {
|
|
782
|
-
|
|
822
|
+
const gnameparts = parts[1].split("/");
|
|
783
823
|
group = gnameparts[0];
|
|
784
824
|
name = gnameparts[1];
|
|
785
825
|
} else {
|
|
@@ -798,7 +838,20 @@ export const parseNodeShrinkwrap = async function (swFile) {
|
|
|
798
838
|
name: "SrcFile",
|
|
799
839
|
value: swFile
|
|
800
840
|
}
|
|
801
|
-
]
|
|
841
|
+
],
|
|
842
|
+
evidence: {
|
|
843
|
+
identity: {
|
|
844
|
+
field: "purl",
|
|
845
|
+
confidence: 1,
|
|
846
|
+
methods: [
|
|
847
|
+
{
|
|
848
|
+
technique: "manifest-analysis",
|
|
849
|
+
confidence: 1,
|
|
850
|
+
value: swFile
|
|
851
|
+
}
|
|
852
|
+
]
|
|
853
|
+
}
|
|
854
|
+
}
|
|
802
855
|
});
|
|
803
856
|
}
|
|
804
857
|
}
|
|
@@ -874,7 +927,7 @@ export const parsePnpmLock = async function (pnpmLock, parentComponent = null) {
|
|
|
874
927
|
}
|
|
875
928
|
const packages = yamlObj.packages;
|
|
876
929
|
const pkgKeys = Object.keys(packages);
|
|
877
|
-
for (
|
|
930
|
+
for (const k in pkgKeys) {
|
|
878
931
|
// Eg: @babel/code-frame/7.10.1
|
|
879
932
|
// In lockfileVersion 6, /@babel/code-frame@7.18.6
|
|
880
933
|
let fullName = pkgKeys[k].replace("/@", "@");
|
|
@@ -885,7 +938,7 @@ export const parsePnpmLock = async function (pnpmLock, parentComponent = null) {
|
|
|
885
938
|
const parts = fullName.split("/");
|
|
886
939
|
const integrity = packages[pkgKeys[k]].resolution.integrity;
|
|
887
940
|
const deps = packages[pkgKeys[k]].dependencies || [];
|
|
888
|
-
|
|
941
|
+
const scope = packages[pkgKeys[k]].dev === true ? "optional" : undefined;
|
|
889
942
|
if (parts && parts.length) {
|
|
890
943
|
let name = "";
|
|
891
944
|
let version = "";
|
|
@@ -952,7 +1005,20 @@ export const parsePnpmLock = async function (pnpmLock, parentComponent = null) {
|
|
|
952
1005
|
name: "SrcFile",
|
|
953
1006
|
value: pnpmLock
|
|
954
1007
|
}
|
|
955
|
-
]
|
|
1008
|
+
],
|
|
1009
|
+
evidence: {
|
|
1010
|
+
identity: {
|
|
1011
|
+
field: "purl",
|
|
1012
|
+
confidence: 1,
|
|
1013
|
+
methods: [
|
|
1014
|
+
{
|
|
1015
|
+
technique: "manifest-analysis",
|
|
1016
|
+
confidence: 1,
|
|
1017
|
+
value: pnpmLock
|
|
1018
|
+
}
|
|
1019
|
+
]
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
956
1022
|
});
|
|
957
1023
|
}
|
|
958
1024
|
}
|
|
@@ -998,7 +1064,20 @@ export const parseBowerJson = async (bowerJsonFile) => {
|
|
|
998
1064
|
name: "SrcFile",
|
|
999
1065
|
value: bowerJsonFile
|
|
1000
1066
|
}
|
|
1001
|
-
]
|
|
1067
|
+
],
|
|
1068
|
+
evidence: {
|
|
1069
|
+
identity: {
|
|
1070
|
+
field: "purl",
|
|
1071
|
+
confidence: 1,
|
|
1072
|
+
methods: [
|
|
1073
|
+
{
|
|
1074
|
+
technique: "manifest-analysis",
|
|
1075
|
+
confidence: 1,
|
|
1076
|
+
value: bowerJsonFile
|
|
1077
|
+
}
|
|
1078
|
+
]
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1002
1081
|
});
|
|
1003
1082
|
} catch (err) {
|
|
1004
1083
|
// continue regardless of error
|
|
@@ -1049,7 +1128,7 @@ export const parseMinJs = async (minJsFile) => {
|
|
|
1049
1128
|
: pkgNameVer.split(" ");
|
|
1050
1129
|
if (tmpB && tmpB.length > 1) {
|
|
1051
1130
|
// Fix #223 - lowercase parsed package name
|
|
1052
|
-
|
|
1131
|
+
const name = tmpB[0].replace(/ /g, "-").trim().toLowerCase();
|
|
1053
1132
|
if (
|
|
1054
1133
|
["copyright", "author", "licensed"].includes(name.toLowerCase())
|
|
1055
1134
|
) {
|
|
@@ -1066,7 +1145,20 @@ export const parseMinJs = async (minJsFile) => {
|
|
|
1066
1145
|
name: "SrcFile",
|
|
1067
1146
|
value: minJsFile
|
|
1068
1147
|
}
|
|
1069
|
-
]
|
|
1148
|
+
],
|
|
1149
|
+
evidence: {
|
|
1150
|
+
identity: {
|
|
1151
|
+
field: "purl",
|
|
1152
|
+
confidence: 0.25,
|
|
1153
|
+
methods: [
|
|
1154
|
+
{
|
|
1155
|
+
technique: "filename",
|
|
1156
|
+
confidence: 0.25,
|
|
1157
|
+
value: minJsFile
|
|
1158
|
+
}
|
|
1159
|
+
]
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1070
1162
|
});
|
|
1071
1163
|
}
|
|
1072
1164
|
return;
|
|
@@ -1111,7 +1203,7 @@ export const parsePom = function (pomFile) {
|
|
|
1111
1203
|
} else if (dependencies && !Array.isArray(dependencies)) {
|
|
1112
1204
|
dependencies = [dependencies];
|
|
1113
1205
|
}
|
|
1114
|
-
for (
|
|
1206
|
+
for (const adep of dependencies) {
|
|
1115
1207
|
const version = adep.version;
|
|
1116
1208
|
let versionStr = undefined;
|
|
1117
1209
|
if (version && version._ && version._.indexOf("$") == -1) {
|
|
@@ -1127,7 +1219,20 @@ export const parsePom = function (pomFile) {
|
|
|
1127
1219
|
name: "SrcFile",
|
|
1128
1220
|
value: pomFile
|
|
1129
1221
|
}
|
|
1130
|
-
]
|
|
1222
|
+
],
|
|
1223
|
+
evidence: {
|
|
1224
|
+
identity: {
|
|
1225
|
+
field: "purl",
|
|
1226
|
+
confidence: 1,
|
|
1227
|
+
methods: [
|
|
1228
|
+
{
|
|
1229
|
+
technique: "manifest-analysis",
|
|
1230
|
+
confidence: 1,
|
|
1231
|
+
value: pomFile
|
|
1232
|
+
}
|
|
1233
|
+
]
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1131
1236
|
});
|
|
1132
1237
|
}
|
|
1133
1238
|
}
|
|
@@ -1150,7 +1255,7 @@ export const parseMavenTree = function (rawOutput) {
|
|
|
1150
1255
|
const tmpA = rawOutput.split("\n");
|
|
1151
1256
|
let last_level = 0;
|
|
1152
1257
|
let last_purl = "";
|
|
1153
|
-
|
|
1258
|
+
const stack = [];
|
|
1154
1259
|
tmpA.forEach((l) => {
|
|
1155
1260
|
if (!includeMavenTestScope && l.trim().endsWith(":test")) {
|
|
1156
1261
|
return;
|
|
@@ -1314,7 +1419,7 @@ export const parseGradleDep = function (
|
|
|
1314
1419
|
) {
|
|
1315
1420
|
last_level = 1;
|
|
1316
1421
|
if (rline.startsWith("+--- project :")) {
|
|
1317
|
-
|
|
1422
|
+
const tmpProj = rline.split("+--- project :");
|
|
1318
1423
|
last_project_purl = `pkg:maven/${tmpProj[1].trim()}@${rootProjectVersion}?type=jar`;
|
|
1319
1424
|
stack = [last_project_purl];
|
|
1320
1425
|
last_purl = last_project_purl;
|
|
@@ -1481,17 +1586,17 @@ export const parseLeinDep = function (rawOutput) {
|
|
|
1481
1586
|
|
|
1482
1587
|
export const parseLeinMap = function (node, keys_cache, deps) {
|
|
1483
1588
|
if (node["map"]) {
|
|
1484
|
-
for (
|
|
1589
|
+
for (const n of node["map"]) {
|
|
1485
1590
|
if (n.length === 2) {
|
|
1486
1591
|
const rootNode = n[0];
|
|
1487
|
-
|
|
1488
|
-
|
|
1592
|
+
const psym = rootNode[0].sym;
|
|
1593
|
+
const version = rootNode[1];
|
|
1489
1594
|
let group = dirname(psym);
|
|
1490
1595
|
if (group === ".") {
|
|
1491
1596
|
group = "";
|
|
1492
1597
|
}
|
|
1493
|
-
|
|
1494
|
-
|
|
1598
|
+
const name = basename(psym);
|
|
1599
|
+
const cacheKey = group + "-" + name + "-" + version;
|
|
1495
1600
|
if (!keys_cache[cacheKey]) {
|
|
1496
1601
|
keys_cache[cacheKey] = true;
|
|
1497
1602
|
deps.push({ group, name, version });
|
|
@@ -1524,7 +1629,7 @@ export const parseGradleProjects = function (rawOutput) {
|
|
|
1524
1629
|
} else if (l.includes("--- Project")) {
|
|
1525
1630
|
const tmpB = l.split("Project ");
|
|
1526
1631
|
if (tmpB && tmpB.length > 1) {
|
|
1527
|
-
|
|
1632
|
+
const projName = tmpB[1].split(" ")[0].replace(/'/g, "");
|
|
1528
1633
|
// Include all projects including test projects
|
|
1529
1634
|
if (projName.startsWith(":")) {
|
|
1530
1635
|
projects.add(projName);
|
|
@@ -1533,7 +1638,7 @@ export const parseGradleProjects = function (rawOutput) {
|
|
|
1533
1638
|
} else if (l.includes("--- project ")) {
|
|
1534
1639
|
const tmpB = l.split("--- project ");
|
|
1535
1640
|
if (tmpB && tmpB.length > 1) {
|
|
1536
|
-
|
|
1641
|
+
const projName = tmpB[1];
|
|
1537
1642
|
if (projName.startsWith(":")) {
|
|
1538
1643
|
projects.add(projName);
|
|
1539
1644
|
}
|
|
@@ -1554,7 +1659,7 @@ export const parseGradleProjects = function (rawOutput) {
|
|
|
1554
1659
|
*/
|
|
1555
1660
|
export const parseGradleProperties = function (rawOutput) {
|
|
1556
1661
|
let rootProject = "root";
|
|
1557
|
-
|
|
1662
|
+
const projects = new Set();
|
|
1558
1663
|
const metadata = { group: "", version: "latest", properties: [] };
|
|
1559
1664
|
if (typeof rawOutput === "string") {
|
|
1560
1665
|
const tmpA = rawOutput.split("\n");
|
|
@@ -1616,7 +1721,7 @@ export const executeGradleProperties = function (dir, rootPath, subProject) {
|
|
|
1616
1721
|
"plain",
|
|
1617
1722
|
"--build-cache"
|
|
1618
1723
|
];
|
|
1619
|
-
|
|
1724
|
+
const gradleCmd = getGradleCommand(dir, rootPath);
|
|
1620
1725
|
if (process.env.GRADLE_ARGS) {
|
|
1621
1726
|
const addArgs = process.env.GRADLE_ARGS.split(" ");
|
|
1622
1727
|
gradlePropertiesArgs = gradlePropertiesArgs.concat(addArgs);
|
|
@@ -1764,7 +1869,7 @@ export const parseKVDep = function (rawOutput) {
|
|
|
1764
1869
|
* @param {string} name License full name
|
|
1765
1870
|
*/
|
|
1766
1871
|
export const findLicenseId = function (name) {
|
|
1767
|
-
for (
|
|
1872
|
+
for (const l of licenseMapping) {
|
|
1768
1873
|
if (l.names.includes(name)) {
|
|
1769
1874
|
return l.exp;
|
|
1770
1875
|
}
|
|
@@ -1781,8 +1886,8 @@ export const findLicenseId = function (name) {
|
|
|
1781
1886
|
*/
|
|
1782
1887
|
export const guessLicenseId = function (content) {
|
|
1783
1888
|
content = content.replace(/\n/g, " ");
|
|
1784
|
-
for (
|
|
1785
|
-
for (
|
|
1889
|
+
for (const l of licenseMapping) {
|
|
1890
|
+
for (const j in l.names) {
|
|
1786
1891
|
if (content.toUpperCase().indexOf(l.names[j].toUpperCase()) > -1) {
|
|
1787
1892
|
return l.exp;
|
|
1788
1893
|
}
|
|
@@ -1817,7 +1922,7 @@ export const getMvnMetadata = async function (pkgList) {
|
|
|
1817
1922
|
if (p.group.indexOf("android") !== -1) {
|
|
1818
1923
|
urlPrefix = ANDROID_MAVEN;
|
|
1819
1924
|
}
|
|
1820
|
-
|
|
1925
|
+
const groupPart = p.group.replace(/\./g, "/");
|
|
1821
1926
|
// Querying maven requires a valid group name
|
|
1822
1927
|
if (!groupPart || groupPart === "") {
|
|
1823
1928
|
cdepList.push(p);
|
|
@@ -1900,7 +2005,7 @@ export const parsePyRequiresDist = function (dist_string) {
|
|
|
1900
2005
|
name = tmpA[0];
|
|
1901
2006
|
} else if (tmpA.length > 1) {
|
|
1902
2007
|
name = tmpA[0];
|
|
1903
|
-
|
|
2008
|
+
const tmpVersion = tmpA[1];
|
|
1904
2009
|
version = tmpVersion.split(",")[0].replace(/[();=&glt><]/g, "");
|
|
1905
2010
|
}
|
|
1906
2011
|
return {
|
|
@@ -1919,7 +2024,7 @@ export const guessPypiMatchingVersion = (versionsList, versionSpecifiers) => {
|
|
|
1919
2024
|
versionSpecifiers = versionSpecifiers.replace(/,/g, " ").split(";")[0];
|
|
1920
2025
|
// Iterate in the reverse order
|
|
1921
2026
|
for (let i = versionsList.length - 1; i > 0; i--) {
|
|
1922
|
-
|
|
2027
|
+
const rv = versionsList[i];
|
|
1923
2028
|
if (satisfies(coerce(rv), versionSpecifiers, true)) {
|
|
1924
2029
|
return rv;
|
|
1925
2030
|
}
|
|
@@ -1939,7 +2044,7 @@ export const getPyMetadata = async function (pkgList, fetchDepsInfo) {
|
|
|
1939
2044
|
return pkgList;
|
|
1940
2045
|
}
|
|
1941
2046
|
const PYPI_URL = "https://pypi.org/pypi/";
|
|
1942
|
-
|
|
2047
|
+
const cdepList = [];
|
|
1943
2048
|
for (const p of pkgList) {
|
|
1944
2049
|
if (!p || !p.name) {
|
|
1945
2050
|
continue;
|
|
@@ -1973,7 +2078,7 @@ export const getPyMetadata = async function (pkgList, fetchDepsInfo) {
|
|
|
1973
2078
|
p.description = body.info.summary;
|
|
1974
2079
|
p.license = findLicenseId(body.info.license);
|
|
1975
2080
|
if (body.info.home_page) {
|
|
1976
|
-
if (body.info.home_page.
|
|
2081
|
+
if (body.info.home_page.includes("git")) {
|
|
1977
2082
|
p.repository = { url: body.info.home_page };
|
|
1978
2083
|
} else {
|
|
1979
2084
|
p.homepage = { url: body.info.home_page };
|
|
@@ -2003,11 +2108,39 @@ export const getPyMetadata = async function (pkgList, fetchDepsInfo) {
|
|
|
2003
2108
|
Object.keys(body.releases || {}),
|
|
2004
2109
|
versionSpecifiers
|
|
2005
2110
|
);
|
|
2111
|
+
// Indicate the confidence with our guess
|
|
2112
|
+
p.evidence = {
|
|
2113
|
+
identity: {
|
|
2114
|
+
field: "version",
|
|
2115
|
+
confidence: 0.75,
|
|
2116
|
+
methods: [
|
|
2117
|
+
{
|
|
2118
|
+
technique: "manifest-analysis",
|
|
2119
|
+
confidence: 0.75,
|
|
2120
|
+
value: `Version specifiers: ${versionSpecifiers}`
|
|
2121
|
+
}
|
|
2122
|
+
]
|
|
2123
|
+
}
|
|
2124
|
+
};
|
|
2006
2125
|
}
|
|
2007
2126
|
// If we have reached here, it means we have not solved the version
|
|
2008
2127
|
// So assume latest
|
|
2009
2128
|
if (!p.version) {
|
|
2010
2129
|
p.version = body.info.version;
|
|
2130
|
+
// Indicate the low confidence
|
|
2131
|
+
p.evidence = {
|
|
2132
|
+
identity: {
|
|
2133
|
+
field: "version",
|
|
2134
|
+
confidence: 0.5,
|
|
2135
|
+
methods: [
|
|
2136
|
+
{
|
|
2137
|
+
technique: "source-code-analysis",
|
|
2138
|
+
confidence: 0.5,
|
|
2139
|
+
value: `PyPI package: ${p.name}`
|
|
2140
|
+
}
|
|
2141
|
+
]
|
|
2142
|
+
}
|
|
2143
|
+
};
|
|
2011
2144
|
}
|
|
2012
2145
|
} else if (p.version !== body.info.version) {
|
|
2013
2146
|
if (!p.properties) {
|
|
@@ -2044,16 +2177,21 @@ export const getPyMetadata = async function (pkgList, fetchDepsInfo) {
|
|
|
2044
2177
|
);
|
|
2045
2178
|
}
|
|
2046
2179
|
p.version = "latest";
|
|
2180
|
+
// Indicate the low confidence
|
|
2181
|
+
p.evidence = {
|
|
2182
|
+
identity: {
|
|
2183
|
+
field: "version",
|
|
2184
|
+
confidence: 0,
|
|
2185
|
+
methods: [
|
|
2186
|
+
{
|
|
2187
|
+
technique: "source-code-analysis",
|
|
2188
|
+
confidence: 0,
|
|
2189
|
+
value: `Module ${p.name}`
|
|
2190
|
+
}
|
|
2191
|
+
]
|
|
2192
|
+
}
|
|
2193
|
+
};
|
|
2047
2194
|
}
|
|
2048
|
-
// Add a property to let the downstream tools know about this assumption
|
|
2049
|
-
// FIXME: Do this correctly with 1.5
|
|
2050
|
-
if (!p.properties) {
|
|
2051
|
-
p.properties = [];
|
|
2052
|
-
}
|
|
2053
|
-
p.properties.push({
|
|
2054
|
-
name: "cdx:pypi:pedigree",
|
|
2055
|
-
value: "unknown"
|
|
2056
|
-
});
|
|
2057
2195
|
cdepList.push(p);
|
|
2058
2196
|
}
|
|
2059
2197
|
}
|
|
@@ -2099,7 +2237,7 @@ export const parsePiplockData = async function (lockData) {
|
|
|
2099
2237
|
Object.keys(depBlock).forEach((p) => {
|
|
2100
2238
|
const pkg = depBlock[p];
|
|
2101
2239
|
if (Object.prototype.hasOwnProperty.call(pkg, "version")) {
|
|
2102
|
-
|
|
2240
|
+
const versionStr = pkg.version.replace("==", "");
|
|
2103
2241
|
pkgList.push({ name: p, version: versionStr });
|
|
2104
2242
|
}
|
|
2105
2243
|
});
|
|
@@ -2184,7 +2322,7 @@ export async function parseReqFile(reqData, fetchDepsInfo) {
|
|
|
2184
2322
|
versionStr = null;
|
|
2185
2323
|
}
|
|
2186
2324
|
if (!tmpA[0].includes("=") && !tmpA[0].trim().includes(" ")) {
|
|
2187
|
-
|
|
2325
|
+
const name = tmpA[0].trim().replace(";", "");
|
|
2188
2326
|
if (!PYTHON_STD_MODULES.includes(name)) {
|
|
2189
2327
|
pkgList.push({
|
|
2190
2328
|
name,
|
|
@@ -2194,8 +2332,8 @@ export async function parseReqFile(reqData, fetchDepsInfo) {
|
|
|
2194
2332
|
}
|
|
2195
2333
|
}
|
|
2196
2334
|
} else if (l.includes("<") && l.includes(">")) {
|
|
2197
|
-
|
|
2198
|
-
|
|
2335
|
+
const tmpA = l.split(">");
|
|
2336
|
+
const name = tmpA[0].trim().replace(";", "");
|
|
2199
2337
|
const versionSpecifiers = l.replace(name, "");
|
|
2200
2338
|
if (!PYTHON_STD_MODULES.includes(name)) {
|
|
2201
2339
|
pkgList.push({
|
|
@@ -2216,7 +2354,7 @@ export async function parseReqFile(reqData, fetchDepsInfo) {
|
|
|
2216
2354
|
tmpA = tmpA.split("#")[0];
|
|
2217
2355
|
}
|
|
2218
2356
|
if (!tmpA[0].trim().includes(" ")) {
|
|
2219
|
-
|
|
2357
|
+
const name = tmpA[0].trim().replace(";", "");
|
|
2220
2358
|
const versionSpecifiers = l.replace(name, "");
|
|
2221
2359
|
if (!PYTHON_STD_MODULES.includes(name)) {
|
|
2222
2360
|
pkgList.push({
|
|
@@ -2237,9 +2375,9 @@ export async function parseReqFile(reqData, fetchDepsInfo) {
|
|
|
2237
2375
|
l = l.split("#")[0];
|
|
2238
2376
|
}
|
|
2239
2377
|
l = l.trim();
|
|
2240
|
-
|
|
2378
|
+
const tmpA = l.split(/(<|>)/);
|
|
2241
2379
|
if (tmpA && tmpA.length === 3) {
|
|
2242
|
-
|
|
2380
|
+
const name = tmpA[0].trim().replace(";", "");
|
|
2243
2381
|
const versionSpecifiers = l.replace(name, "");
|
|
2244
2382
|
if (!PYTHON_STD_MODULES.includes(name)) {
|
|
2245
2383
|
pkgList.push({
|
|
@@ -2255,7 +2393,7 @@ export async function parseReqFile(reqData, fetchDepsInfo) {
|
|
|
2255
2393
|
});
|
|
2256
2394
|
}
|
|
2257
2395
|
} else if (!l.includes(" ")) {
|
|
2258
|
-
|
|
2396
|
+
const name = l.replace(";", "");
|
|
2259
2397
|
const versionSpecifiers = l.replace(name, "");
|
|
2260
2398
|
if (!PYTHON_STD_MODULES.includes(name)) {
|
|
2261
2399
|
pkgList.push({
|
|
@@ -2286,6 +2424,7 @@ export async function parseReqFile(reqData, fetchDepsInfo) {
|
|
|
2286
2424
|
*/
|
|
2287
2425
|
export const getPyModules = async (src, epkgList) => {
|
|
2288
2426
|
const allImports = {};
|
|
2427
|
+
const dependenciesList = [];
|
|
2289
2428
|
const modList = findAppModules(src, "python");
|
|
2290
2429
|
const pyDefaultModules = new Set(PYTHON_STD_MODULES);
|
|
2291
2430
|
const filteredModList = modList.filter(
|
|
@@ -2323,7 +2462,13 @@ export const getPyModules = async (src, epkgList) => {
|
|
|
2323
2462
|
pkgList = pkgList.filter((p) => !pkgMaps.includes(p.name));
|
|
2324
2463
|
}
|
|
2325
2464
|
pkgList = await getPyMetadata(pkgList, true);
|
|
2326
|
-
|
|
2465
|
+
for (const p of pkgList) {
|
|
2466
|
+
dependenciesList.push({
|
|
2467
|
+
ref: `pkg:pypi/${p.name}@${p.version}`.toLowerCase(),
|
|
2468
|
+
dependsOn: []
|
|
2469
|
+
});
|
|
2470
|
+
}
|
|
2471
|
+
return { allImports, pkgList, dependenciesList };
|
|
2327
2472
|
};
|
|
2328
2473
|
|
|
2329
2474
|
/**
|
|
@@ -2429,7 +2574,7 @@ export const getRepoLicense = async function (repoUrl, repoMetadata) {
|
|
|
2429
2574
|
const group = repoMetadata.group;
|
|
2430
2575
|
const name = repoMetadata.name;
|
|
2431
2576
|
if (group && name) {
|
|
2432
|
-
for (
|
|
2577
|
+
for (const akLic of knownLicenses) {
|
|
2433
2578
|
if (akLic.group === "." && akLic.name === name) {
|
|
2434
2579
|
return akLic.license;
|
|
2435
2580
|
} else if (
|
|
@@ -2471,7 +2616,7 @@ export const getGoPkgLicense = async function (repoMetadata) {
|
|
|
2471
2616
|
}
|
|
2472
2617
|
const licenseIds = licenses.split(", ");
|
|
2473
2618
|
const licList = [];
|
|
2474
|
-
for (
|
|
2619
|
+
for (const id of licenseIds) {
|
|
2475
2620
|
const alicense = {
|
|
2476
2621
|
id: id
|
|
2477
2622
|
};
|
|
@@ -2554,23 +2699,33 @@ export const parseGoModData = async function (goModData, gosumMap) {
|
|
|
2554
2699
|
if (!isModReplacement) {
|
|
2555
2700
|
// Add group, name and version component properties for required modules
|
|
2556
2701
|
const version = tmpA[1];
|
|
2557
|
-
|
|
2702
|
+
const gosumHash = gosumMap[`${tmpA[0]}/${version}`];
|
|
2558
2703
|
// The hash for this version was not found in go.sum, so skip as it is most likely being replaced.
|
|
2559
2704
|
if (gosumHash === undefined) {
|
|
2560
2705
|
continue;
|
|
2561
2706
|
}
|
|
2562
|
-
|
|
2707
|
+
const component = await getGoPkgComponent(
|
|
2708
|
+
"",
|
|
2709
|
+
tmpA[0],
|
|
2710
|
+
version,
|
|
2711
|
+
gosumHash
|
|
2712
|
+
);
|
|
2563
2713
|
pkgComponentsList.push(component);
|
|
2564
2714
|
} else {
|
|
2565
2715
|
// Add group, name and version component properties for replacement modules
|
|
2566
2716
|
const version = tmpA[3];
|
|
2567
2717
|
|
|
2568
|
-
|
|
2718
|
+
const gosumHash = gosumMap[`${tmpA[2]}/${version}`];
|
|
2569
2719
|
// The hash for this version was not found in go.sum, so skip.
|
|
2570
2720
|
if (gosumHash === undefined) {
|
|
2571
2721
|
continue;
|
|
2572
2722
|
}
|
|
2573
|
-
|
|
2723
|
+
const component = await getGoPkgComponent(
|
|
2724
|
+
"",
|
|
2725
|
+
tmpA[2],
|
|
2726
|
+
version,
|
|
2727
|
+
gosumHash
|
|
2728
|
+
);
|
|
2574
2729
|
pkgComponentsList.push(component);
|
|
2575
2730
|
}
|
|
2576
2731
|
}
|
|
@@ -2590,7 +2745,7 @@ export const parseGoListDep = async function (rawOutput, gosumMap) {
|
|
|
2590
2745
|
const deps = [];
|
|
2591
2746
|
const keys_cache = {};
|
|
2592
2747
|
const pkgs = rawOutput.split("\n");
|
|
2593
|
-
for (
|
|
2748
|
+
for (const l of pkgs) {
|
|
2594
2749
|
const verArr = l.trim().replace(new RegExp("[\"']", "g"), "").split(" ");
|
|
2595
2750
|
|
|
2596
2751
|
if (verArr && verArr.length === 5) {
|
|
@@ -2599,8 +2754,8 @@ export const parseGoListDep = async function (rawOutput, gosumMap) {
|
|
|
2599
2754
|
if (!keys_cache[key]) {
|
|
2600
2755
|
keys_cache[key] = key;
|
|
2601
2756
|
const version = verArr[1];
|
|
2602
|
-
|
|
2603
|
-
|
|
2757
|
+
const gosumHash = gosumMap[`${verArr[0]}/${version}`];
|
|
2758
|
+
const component = await getGoPkgComponent(
|
|
2604
2759
|
"",
|
|
2605
2760
|
verArr[0],
|
|
2606
2761
|
version,
|
|
@@ -2655,7 +2810,7 @@ export const parseGosumData = async function (gosumData) {
|
|
|
2655
2810
|
return pkgList;
|
|
2656
2811
|
}
|
|
2657
2812
|
const pkgs = gosumData.split("\n");
|
|
2658
|
-
for (
|
|
2813
|
+
for (const l of pkgs) {
|
|
2659
2814
|
// look for lines containing go.mod
|
|
2660
2815
|
if (l.indexOf("go.mod") > -1) {
|
|
2661
2816
|
const tmpA = l.split(" ");
|
|
@@ -2693,7 +2848,7 @@ export const parseGopkgData = async function (gopkgData) {
|
|
|
2693
2848
|
}
|
|
2694
2849
|
let pkg = null;
|
|
2695
2850
|
const pkgs = gopkgData.split("\n");
|
|
2696
|
-
for (
|
|
2851
|
+
for (const l of pkgs) {
|
|
2697
2852
|
let key = null;
|
|
2698
2853
|
let value = null;
|
|
2699
2854
|
if (l.indexOf("[[projects]]") > -1) {
|
|
@@ -2741,7 +2896,7 @@ export const parseGoVersionData = async function (buildInfoData) {
|
|
|
2741
2896
|
return pkgList;
|
|
2742
2897
|
}
|
|
2743
2898
|
const pkgs = buildInfoData.split("\n");
|
|
2744
|
-
for (
|
|
2899
|
+
for (const i in pkgs) {
|
|
2745
2900
|
const l = pkgs[i].trim().replace(/\t/g, " ");
|
|
2746
2901
|
if (!l.startsWith("dep")) {
|
|
2747
2902
|
continue;
|
|
@@ -2755,7 +2910,7 @@ export const parseGoVersionData = async function (buildInfoData) {
|
|
|
2755
2910
|
if (tmpA.length == 4) {
|
|
2756
2911
|
hash = tmpA[tmpA.length - 1].replace("h1:", "sha256-");
|
|
2757
2912
|
}
|
|
2758
|
-
|
|
2913
|
+
const component = await getGoPkgComponent("", name, tmpA[2].trim(), hash);
|
|
2759
2914
|
pkgList.push(component);
|
|
2760
2915
|
}
|
|
2761
2916
|
return pkgList;
|
|
@@ -2958,7 +3113,7 @@ export const getDartMetadata = async function (pkgList) {
|
|
|
2958
3113
|
});
|
|
2959
3114
|
if (res && res.body) {
|
|
2960
3115
|
const versions = res.body.versions;
|
|
2961
|
-
for (
|
|
3116
|
+
for (const v of versions) {
|
|
2962
3117
|
if (p.version === v.version) {
|
|
2963
3118
|
const pubspec = v.pubspec;
|
|
2964
3119
|
p.description = pubspec.description;
|
|
@@ -2982,7 +3137,7 @@ export const getDartMetadata = async function (pkgList) {
|
|
|
2982
3137
|
};
|
|
2983
3138
|
|
|
2984
3139
|
export const parseCargoTomlData = async function (cargoData) {
|
|
2985
|
-
|
|
3140
|
+
const pkgList = [];
|
|
2986
3141
|
if (!cargoData) {
|
|
2987
3142
|
return pkgList;
|
|
2988
3143
|
}
|
|
@@ -3031,7 +3186,7 @@ export const parseCargoTomlData = async function (cargoData) {
|
|
|
3031
3186
|
pkgList.push(pkg);
|
|
3032
3187
|
}
|
|
3033
3188
|
pkg = undefined;
|
|
3034
|
-
|
|
3189
|
+
const tmpA = l.split(" = ");
|
|
3035
3190
|
let tmpB = undefined;
|
|
3036
3191
|
let name = tmpA[0];
|
|
3037
3192
|
let version = undefined;
|
|
@@ -3179,7 +3334,7 @@ export const parsePubLockData = async function (pubLockData) {
|
|
|
3179
3334
|
}
|
|
3180
3335
|
};
|
|
3181
3336
|
|
|
3182
|
-
export const parsePubYamlData =
|
|
3337
|
+
export const parsePubYamlData = function (pubYamlData) {
|
|
3183
3338
|
const pkgList = [];
|
|
3184
3339
|
let yamlObj = undefined;
|
|
3185
3340
|
try {
|
|
@@ -3199,7 +3354,7 @@ export const parsePubYamlData = async function (pubYamlData) {
|
|
|
3199
3354
|
return pkgList;
|
|
3200
3355
|
};
|
|
3201
3356
|
|
|
3202
|
-
export const parseHelmYamlData =
|
|
3357
|
+
export const parseHelmYamlData = function (helmData) {
|
|
3203
3358
|
const pkgList = [];
|
|
3204
3359
|
let yamlObj = undefined;
|
|
3205
3360
|
try {
|
|
@@ -3211,7 +3366,7 @@ export const parseHelmYamlData = async function (helmData) {
|
|
|
3211
3366
|
return pkgList;
|
|
3212
3367
|
}
|
|
3213
3368
|
if (yamlObj.name && yamlObj.version) {
|
|
3214
|
-
|
|
3369
|
+
const pkg = {
|
|
3215
3370
|
name: yamlObj.name,
|
|
3216
3371
|
description: yamlObj.description || "",
|
|
3217
3372
|
version: yamlObj.version
|
|
@@ -3223,7 +3378,7 @@ export const parseHelmYamlData = async function (helmData) {
|
|
|
3223
3378
|
}
|
|
3224
3379
|
if (yamlObj.dependencies) {
|
|
3225
3380
|
for (const hd of yamlObj.dependencies) {
|
|
3226
|
-
|
|
3381
|
+
const pkg = {
|
|
3227
3382
|
name: hd.name,
|
|
3228
3383
|
version: hd.version // This could have * so not precise
|
|
3229
3384
|
};
|
|
@@ -3238,7 +3393,7 @@ export const parseHelmYamlData = async function (helmData) {
|
|
|
3238
3393
|
for (const key of Object.keys(yamlObj.entries[he])) {
|
|
3239
3394
|
const hd = yamlObj.entries[he][key];
|
|
3240
3395
|
if (hd.name && hd.version) {
|
|
3241
|
-
|
|
3396
|
+
const pkg = {
|
|
3242
3397
|
name: hd.name,
|
|
3243
3398
|
version: hd.version,
|
|
3244
3399
|
description: hd.description || ""
|
|
@@ -3327,7 +3482,7 @@ export const recurseImageNameLookup = (keyValueObj, pkgList, imgList) => {
|
|
|
3327
3482
|
return imgList;
|
|
3328
3483
|
};
|
|
3329
3484
|
|
|
3330
|
-
export const parseContainerSpecData =
|
|
3485
|
+
export const parseContainerSpecData = function (dcData) {
|
|
3331
3486
|
const pkgList = [];
|
|
3332
3487
|
const imgList = [];
|
|
3333
3488
|
if (!dcData.includes("image") && !dcData.includes("kind")) {
|
|
@@ -3397,7 +3552,7 @@ export const parseContainerSpecData = async function (dcData) {
|
|
|
3397
3552
|
export const identifyFlow = function (processingObj) {
|
|
3398
3553
|
let flow = "unknown";
|
|
3399
3554
|
if (processingObj.sinkId) {
|
|
3400
|
-
|
|
3555
|
+
const sinkId = processingObj.sinkId.toLowerCase();
|
|
3401
3556
|
if (sinkId.endsWith("write")) {
|
|
3402
3557
|
flow = "inbound";
|
|
3403
3558
|
} else if (sinkId.endsWith("read")) {
|
|
@@ -3427,7 +3582,7 @@ export const parsePrivadoFile = function (f) {
|
|
|
3427
3582
|
return servlist;
|
|
3428
3583
|
}
|
|
3429
3584
|
const jsonData = JSON.parse(pData);
|
|
3430
|
-
|
|
3585
|
+
const aservice = {
|
|
3431
3586
|
"x-trust-boundary": false,
|
|
3432
3587
|
properties: [],
|
|
3433
3588
|
data: [],
|
|
@@ -3472,9 +3627,9 @@ export const parsePrivadoFile = function (f) {
|
|
|
3472
3627
|
// Find endpoints
|
|
3473
3628
|
if (jsonData.collections) {
|
|
3474
3629
|
const endpoints = [];
|
|
3475
|
-
for (
|
|
3476
|
-
for (
|
|
3477
|
-
for (
|
|
3630
|
+
for (const c of jsonData.collections) {
|
|
3631
|
+
for (const occ of c.collections) {
|
|
3632
|
+
for (const e of occ.occurrences) {
|
|
3478
3633
|
if (e.endPoint) {
|
|
3479
3634
|
endpoints.push(e.endPoint);
|
|
3480
3635
|
}
|
|
@@ -3485,7 +3640,7 @@ export const parsePrivadoFile = function (f) {
|
|
|
3485
3640
|
}
|
|
3486
3641
|
// Capture violations
|
|
3487
3642
|
if (jsonData.violations) {
|
|
3488
|
-
for (
|
|
3643
|
+
for (const v of jsonData.violations) {
|
|
3489
3644
|
aservice.properties.push({
|
|
3490
3645
|
name: "privado_violations",
|
|
3491
3646
|
value: v.policyId
|
|
@@ -3505,7 +3660,7 @@ export const parsePrivadoFile = function (f) {
|
|
|
3505
3660
|
return servlist;
|
|
3506
3661
|
};
|
|
3507
3662
|
|
|
3508
|
-
export const parseOpenapiSpecData =
|
|
3663
|
+
export const parseOpenapiSpecData = function (oaData) {
|
|
3509
3664
|
const servlist = [];
|
|
3510
3665
|
if (!oaData) {
|
|
3511
3666
|
return servlist;
|
|
@@ -3555,7 +3710,7 @@ export const parseOpenapiSpecData = async function (oaData) {
|
|
|
3555
3710
|
return servlist;
|
|
3556
3711
|
};
|
|
3557
3712
|
|
|
3558
|
-
export const parseCabalData =
|
|
3713
|
+
export const parseCabalData = function (cabalData) {
|
|
3559
3714
|
const pkgList = [];
|
|
3560
3715
|
if (!cabalData) {
|
|
3561
3716
|
return pkgList;
|
|
@@ -3582,7 +3737,7 @@ export const parseCabalData = async function (cabalData) {
|
|
|
3582
3737
|
return pkgList;
|
|
3583
3738
|
};
|
|
3584
3739
|
|
|
3585
|
-
export const parseMixLockData =
|
|
3740
|
+
export const parseMixLockData = function (mixData) {
|
|
3586
3741
|
const pkgList = [];
|
|
3587
3742
|
if (!mixData) {
|
|
3588
3743
|
return pkgList;
|
|
@@ -3608,7 +3763,7 @@ export const parseMixLockData = async function (mixData) {
|
|
|
3608
3763
|
return pkgList;
|
|
3609
3764
|
};
|
|
3610
3765
|
|
|
3611
|
-
export const parseGitHubWorkflowData =
|
|
3766
|
+
export const parseGitHubWorkflowData = function (ghwData) {
|
|
3612
3767
|
const pkgList = [];
|
|
3613
3768
|
const keys_cache = {};
|
|
3614
3769
|
if (!ghwData) {
|
|
@@ -3650,7 +3805,7 @@ export const parseGitHubWorkflowData = async function (ghwData) {
|
|
|
3650
3805
|
return pkgList;
|
|
3651
3806
|
};
|
|
3652
3807
|
|
|
3653
|
-
export const parseCloudBuildData =
|
|
3808
|
+
export const parseCloudBuildData = function (cbwData) {
|
|
3654
3809
|
const pkgList = [];
|
|
3655
3810
|
const keys_cache = {};
|
|
3656
3811
|
if (!cbwData) {
|
|
@@ -3666,7 +3821,7 @@ export const parseCloudBuildData = async function (cbwData) {
|
|
|
3666
3821
|
const tmpA = step.name.split(":");
|
|
3667
3822
|
if (tmpA.length === 2) {
|
|
3668
3823
|
let group = dirname(tmpA[0]);
|
|
3669
|
-
|
|
3824
|
+
const name = basename(tmpA[0]);
|
|
3670
3825
|
if (group === ".") {
|
|
3671
3826
|
group = "";
|
|
3672
3827
|
}
|
|
@@ -3687,7 +3842,7 @@ export const parseCloudBuildData = async function (cbwData) {
|
|
|
3687
3842
|
return pkgList;
|
|
3688
3843
|
};
|
|
3689
3844
|
|
|
3690
|
-
export const parseConanLockData =
|
|
3845
|
+
export const parseConanLockData = function (conanLockData) {
|
|
3691
3846
|
const pkgList = [];
|
|
3692
3847
|
if (!conanLockData) {
|
|
3693
3848
|
return pkgList;
|
|
@@ -3697,7 +3852,7 @@ export const parseConanLockData = async function (conanLockData) {
|
|
|
3697
3852
|
return pkgList;
|
|
3698
3853
|
}
|
|
3699
3854
|
const nodes = graphLock.graph_lock.nodes;
|
|
3700
|
-
for (
|
|
3855
|
+
for (const nk of Object.keys(nodes)) {
|
|
3701
3856
|
if (nodes[nk].ref) {
|
|
3702
3857
|
const tmpA = nodes[nk].ref.split("/");
|
|
3703
3858
|
if (tmpA.length === 2) {
|
|
@@ -3708,7 +3863,7 @@ export const parseConanLockData = async function (conanLockData) {
|
|
|
3708
3863
|
return pkgList;
|
|
3709
3864
|
};
|
|
3710
3865
|
|
|
3711
|
-
export const parseConanData =
|
|
3866
|
+
export const parseConanData = function (conanData) {
|
|
3712
3867
|
const pkgList = [];
|
|
3713
3868
|
if (!conanData) {
|
|
3714
3869
|
return pkgList;
|
|
@@ -3737,7 +3892,7 @@ export const parseLeiningenData = function (leinData) {
|
|
|
3737
3892
|
leinData = "(defproject" + tmpArr[1];
|
|
3738
3893
|
}
|
|
3739
3894
|
const ednData = parseEDNString(leinData);
|
|
3740
|
-
for (
|
|
3895
|
+
for (const k of Object.keys(ednData)) {
|
|
3741
3896
|
if (k === "list") {
|
|
3742
3897
|
ednData[k].forEach((jk) => {
|
|
3743
3898
|
if (Array.isArray(jk)) {
|
|
@@ -3768,7 +3923,7 @@ export const parseEdnData = function (rawEdnData) {
|
|
|
3768
3923
|
}
|
|
3769
3924
|
const ednData = parseEDNString(rawEdnData);
|
|
3770
3925
|
const pkgCache = {};
|
|
3771
|
-
for (
|
|
3926
|
+
for (const k of Object.keys(ednData)) {
|
|
3772
3927
|
if (k === "map") {
|
|
3773
3928
|
ednData[k].forEach((jk) => {
|
|
3774
3929
|
if (Array.isArray(jk)) {
|
|
@@ -3815,7 +3970,7 @@ export const parseEdnData = function (rawEdnData) {
|
|
|
3815
3970
|
|
|
3816
3971
|
export const parseNupkg = async function (nupkgFile) {
|
|
3817
3972
|
const pkgList = [];
|
|
3818
|
-
|
|
3973
|
+
const pkg = { group: "" };
|
|
3819
3974
|
let nuspecData = await readZipEntry(nupkgFile, ".nuspec");
|
|
3820
3975
|
// Remove byte order mark
|
|
3821
3976
|
if (nuspecData.charCodeAt(0) === 0xfeff) {
|
|
@@ -3850,6 +4005,19 @@ export const parseNupkg = async function (nupkgFile) {
|
|
|
3850
4005
|
value: nupkgFile
|
|
3851
4006
|
}
|
|
3852
4007
|
];
|
|
4008
|
+
pkg.evidence = {
|
|
4009
|
+
identity: {
|
|
4010
|
+
field: "purl",
|
|
4011
|
+
confidence: 1,
|
|
4012
|
+
methods: [
|
|
4013
|
+
{
|
|
4014
|
+
technique: "binary-analysis",
|
|
4015
|
+
confidence: 1,
|
|
4016
|
+
value: nupkgFile
|
|
4017
|
+
}
|
|
4018
|
+
]
|
|
4019
|
+
}
|
|
4020
|
+
};
|
|
3853
4021
|
pkgList.push(pkg);
|
|
3854
4022
|
if (fetchLicenses) {
|
|
3855
4023
|
return await getNugetMetadata(pkgList);
|
|
@@ -3875,9 +4043,9 @@ export const parseCsPkgData = async function (pkgData) {
|
|
|
3875
4043
|
return pkgList;
|
|
3876
4044
|
}
|
|
3877
4045
|
packages = packages[0].package;
|
|
3878
|
-
for (
|
|
4046
|
+
for (const i in packages) {
|
|
3879
4047
|
const p = packages[i].$;
|
|
3880
|
-
|
|
4048
|
+
const pkg = { group: "" };
|
|
3881
4049
|
pkg.name = p.id;
|
|
3882
4050
|
pkg.version = p.version;
|
|
3883
4051
|
pkgList.push(pkg);
|
|
@@ -3907,12 +4075,12 @@ export const parseCsProjData = async function (csProjData) {
|
|
|
3907
4075
|
}
|
|
3908
4076
|
const project = projects[0];
|
|
3909
4077
|
if (project.ItemGroup && project.ItemGroup.length) {
|
|
3910
|
-
for (
|
|
4078
|
+
for (const i in project.ItemGroup) {
|
|
3911
4079
|
const item = project.ItemGroup[i];
|
|
3912
4080
|
// .net core use PackageReference
|
|
3913
|
-
for (
|
|
4081
|
+
for (const j in item.PackageReference) {
|
|
3914
4082
|
const pref = item.PackageReference[j].$;
|
|
3915
|
-
|
|
4083
|
+
const pkg = { group: "" };
|
|
3916
4084
|
if (!pref.Include || pref.Include.includes(".csproj")) {
|
|
3917
4085
|
continue;
|
|
3918
4086
|
}
|
|
@@ -3921,9 +4089,9 @@ export const parseCsProjData = async function (csProjData) {
|
|
|
3921
4089
|
pkgList.push(pkg);
|
|
3922
4090
|
}
|
|
3923
4091
|
// .net framework use Reference
|
|
3924
|
-
for (
|
|
4092
|
+
for (const j in item.Reference) {
|
|
3925
4093
|
const pref = item.Reference[j].$;
|
|
3926
|
-
|
|
4094
|
+
const pkg = { group: "" };
|
|
3927
4095
|
if (!pref.Include || pref.Include.includes(".csproj")) {
|
|
3928
4096
|
continue;
|
|
3929
4097
|
}
|
|
@@ -3953,7 +4121,7 @@ export const parseCsProjAssetsData = async function (csProjData) {
|
|
|
3953
4121
|
if (!assetData || !assetData.libraries) {
|
|
3954
4122
|
return pkgList;
|
|
3955
4123
|
}
|
|
3956
|
-
for (
|
|
4124
|
+
for (const alib of Object.keys(assetData.libraries)) {
|
|
3957
4125
|
// Skip os runtime packages
|
|
3958
4126
|
if (alib.startsWith("runtime")) {
|
|
3959
4127
|
continue;
|
|
@@ -3992,8 +4160,8 @@ export const parseCsPkgLockData = async function (csLockData) {
|
|
|
3992
4160
|
if (!assetData || !assetData.dependencies) {
|
|
3993
4161
|
return pkgList;
|
|
3994
4162
|
}
|
|
3995
|
-
for (
|
|
3996
|
-
for (
|
|
4163
|
+
for (const aversion of Object.keys(assetData.dependencies)) {
|
|
4164
|
+
for (const alib of Object.keys(assetData.dependencies[aversion])) {
|
|
3997
4165
|
const libData = assetData.dependencies[aversion][alib];
|
|
3998
4166
|
pkg = {
|
|
3999
4167
|
group: "",
|
|
@@ -4135,15 +4303,15 @@ export const parseComposerLock = function (pkgLockFile) {
|
|
|
4135
4303
|
return [];
|
|
4136
4304
|
}
|
|
4137
4305
|
if (lockData) {
|
|
4138
|
-
|
|
4306
|
+
const packages = {};
|
|
4139
4307
|
if (lockData["packages"]) {
|
|
4140
4308
|
packages["required"] = lockData["packages"];
|
|
4141
4309
|
}
|
|
4142
4310
|
if (lockData["packages-dev"]) {
|
|
4143
4311
|
packages["optional"] = lockData["packages-dev"];
|
|
4144
4312
|
}
|
|
4145
|
-
for (
|
|
4146
|
-
for (
|
|
4313
|
+
for (const compScope in packages) {
|
|
4314
|
+
for (const i in packages[compScope]) {
|
|
4147
4315
|
const pkg = packages[compScope][i];
|
|
4148
4316
|
// Be extra cautious. Potential fix for #236
|
|
4149
4317
|
if (!pkg || !pkg.name || !pkg.version) {
|
|
@@ -4153,7 +4321,7 @@ export const parseComposerLock = function (pkgLockFile) {
|
|
|
4153
4321
|
if (group === ".") {
|
|
4154
4322
|
group = "";
|
|
4155
4323
|
}
|
|
4156
|
-
|
|
4324
|
+
const name = basename(pkg.name);
|
|
4157
4325
|
pkgList.push({
|
|
4158
4326
|
group: group,
|
|
4159
4327
|
name: name,
|
|
@@ -4171,7 +4339,20 @@ export const parseComposerLock = function (pkgLockFile) {
|
|
|
4171
4339
|
name: "SrcFile",
|
|
4172
4340
|
value: pkgLockFile
|
|
4173
4341
|
}
|
|
4174
|
-
]
|
|
4342
|
+
],
|
|
4343
|
+
evidence: {
|
|
4344
|
+
identity: {
|
|
4345
|
+
field: "purl",
|
|
4346
|
+
confidence: 1,
|
|
4347
|
+
methods: [
|
|
4348
|
+
{
|
|
4349
|
+
technique: "manifest-analysis",
|
|
4350
|
+
confidence: 1,
|
|
4351
|
+
value: pkgLockFile
|
|
4352
|
+
}
|
|
4353
|
+
]
|
|
4354
|
+
}
|
|
4355
|
+
}
|
|
4175
4356
|
});
|
|
4176
4357
|
}
|
|
4177
4358
|
}
|
|
@@ -4190,7 +4371,7 @@ export const parseSbtLock = function (pkgLockFile) {
|
|
|
4190
4371
|
if (existsSync(pkgLockFile)) {
|
|
4191
4372
|
const lockData = JSON.parse(readFileSync(pkgLockFile, "utf8"));
|
|
4192
4373
|
if (lockData && lockData.dependencies) {
|
|
4193
|
-
for (
|
|
4374
|
+
for (const pkg of lockData.dependencies) {
|
|
4194
4375
|
const artifacts = pkg.artifacts || undefined;
|
|
4195
4376
|
let integrity = "";
|
|
4196
4377
|
if (artifacts && artifacts.length) {
|
|
@@ -4215,7 +4396,20 @@ export const parseSbtLock = function (pkgLockFile) {
|
|
|
4215
4396
|
name: "SrcFile",
|
|
4216
4397
|
value: pkgLockFile
|
|
4217
4398
|
}
|
|
4218
|
-
]
|
|
4399
|
+
],
|
|
4400
|
+
evidence: {
|
|
4401
|
+
identity: {
|
|
4402
|
+
field: "purl",
|
|
4403
|
+
confidence: 1,
|
|
4404
|
+
methods: [
|
|
4405
|
+
{
|
|
4406
|
+
technique: "manifest-analysis",
|
|
4407
|
+
confidence: 1,
|
|
4408
|
+
value: pkgLockFile
|
|
4409
|
+
}
|
|
4410
|
+
]
|
|
4411
|
+
}
|
|
4412
|
+
}
|
|
4219
4413
|
});
|
|
4220
4414
|
}
|
|
4221
4415
|
}
|
|
@@ -4240,15 +4434,15 @@ export const convertOSQueryResults = function (
|
|
|
4240
4434
|
if (res.version) {
|
|
4241
4435
|
const version = res.version;
|
|
4242
4436
|
let name = res.name || res.device_id;
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4437
|
+
const group = "";
|
|
4438
|
+
const subpath = res.path || res.admindir || res.source;
|
|
4439
|
+
const publisher = res.maintainer || res.creator;
|
|
4246
4440
|
let scope = undefined;
|
|
4247
|
-
|
|
4441
|
+
const compScope = res.priority;
|
|
4248
4442
|
if (["required", "optional", "excluded"].includes(compScope)) {
|
|
4249
4443
|
scope = compScope;
|
|
4250
4444
|
}
|
|
4251
|
-
|
|
4445
|
+
const description =
|
|
4252
4446
|
res.description ||
|
|
4253
4447
|
res.arguments ||
|
|
4254
4448
|
res.device ||
|
|
@@ -4293,7 +4487,7 @@ export const _swiftDepPkgList = (
|
|
|
4293
4487
|
jsonData
|
|
4294
4488
|
) => {
|
|
4295
4489
|
if (jsonData && jsonData.dependencies) {
|
|
4296
|
-
for (
|
|
4490
|
+
for (const adep of jsonData.dependencies) {
|
|
4297
4491
|
const urlOrPath = adep.url || adep.path;
|
|
4298
4492
|
const apkg = {
|
|
4299
4493
|
group: adep.identity || "",
|
|
@@ -4333,7 +4527,7 @@ export const _swiftDepPkgList = (
|
|
|
4333
4527
|
// Handle the immediate dependencies before recursing
|
|
4334
4528
|
if (adep.dependencies && adep.dependencies.length) {
|
|
4335
4529
|
const deplist = [];
|
|
4336
|
-
for (
|
|
4530
|
+
for (const cdep of adep.dependencies) {
|
|
4337
4531
|
const deppurl = new PackageURL(
|
|
4338
4532
|
"swift",
|
|
4339
4533
|
cdep.identity || "",
|
|
@@ -4380,7 +4574,7 @@ export const parseSwiftJsonTree = (rawOutput, pkgFile) => {
|
|
|
4380
4574
|
}
|
|
4381
4575
|
const pkgList = [];
|
|
4382
4576
|
const dependenciesList = [];
|
|
4383
|
-
|
|
4577
|
+
const depKeys = {};
|
|
4384
4578
|
let rootPkg = {};
|
|
4385
4579
|
let jsonData = {};
|
|
4386
4580
|
try {
|
|
@@ -4475,7 +4669,20 @@ export const parseSwiftResolved = (resolvedFile) => {
|
|
|
4475
4669
|
name: "SrcFile",
|
|
4476
4670
|
value: resolvedFile
|
|
4477
4671
|
}
|
|
4478
|
-
]
|
|
4672
|
+
],
|
|
4673
|
+
evidence: {
|
|
4674
|
+
identity: {
|
|
4675
|
+
field: "purl",
|
|
4676
|
+
confidence: 1,
|
|
4677
|
+
methods: [
|
|
4678
|
+
{
|
|
4679
|
+
technique: "manifest-analysis",
|
|
4680
|
+
confidence: 1,
|
|
4681
|
+
value: resolvedFile
|
|
4682
|
+
}
|
|
4683
|
+
]
|
|
4684
|
+
}
|
|
4685
|
+
}
|
|
4479
4686
|
};
|
|
4480
4687
|
const repLocation = adep.location || adep.repositoryURL;
|
|
4481
4688
|
if (repLocation) {
|
|
@@ -4497,7 +4704,7 @@ export const parseSwiftResolved = (resolvedFile) => {
|
|
|
4497
4704
|
* @param {string} basePath Path to the maven project
|
|
4498
4705
|
*/
|
|
4499
4706
|
export const collectMvnDependencies = function (mavenCmd, basePath) {
|
|
4500
|
-
|
|
4707
|
+
const tempDir = mkdtempSync(join(tmpdir(), "mvn-deps-"));
|
|
4501
4708
|
console.log(
|
|
4502
4709
|
`Executing 'mvn dependency:copy-dependencies -DoutputDirectory=${tempDir} -DexcludeTransitive=true -DincludeScope=runtime' in ${basePath}`
|
|
4503
4710
|
);
|
|
@@ -4555,7 +4762,7 @@ export const collectJarNS = function (jarPath) {
|
|
|
4555
4762
|
// Execute jar tvf to get class names
|
|
4556
4763
|
const jarFiles = getAllFiles(jarPath, "**/*.jar");
|
|
4557
4764
|
if (jarFiles && jarFiles.length) {
|
|
4558
|
-
for (
|
|
4765
|
+
for (const jf of jarFiles) {
|
|
4559
4766
|
const jarname = basename(jf);
|
|
4560
4767
|
if (DEBUG_MODE) {
|
|
4561
4768
|
console.log(`Executing 'jar tf ${jf}'`);
|
|
@@ -4659,7 +4866,7 @@ export { _encodeForPurl as encodeForPurl };
|
|
|
4659
4866
|
* @return pkgList Package list
|
|
4660
4867
|
*/
|
|
4661
4868
|
export const extractJarArchive = function (jarFile, tempDir) {
|
|
4662
|
-
|
|
4869
|
+
const pkgList = [];
|
|
4663
4870
|
let jarFiles = [];
|
|
4664
4871
|
const fname = basename(jarFile);
|
|
4665
4872
|
let pomname = undefined;
|
|
@@ -4674,7 +4881,7 @@ export const extractJarArchive = function (jarFile, tempDir) {
|
|
|
4674
4881
|
copyFileSync(jarFile, join(tempDir, fname), constants.COPYFILE_FICLONE);
|
|
4675
4882
|
}
|
|
4676
4883
|
if (jarFile.endsWith(".war") || jarFile.endsWith(".hpi")) {
|
|
4677
|
-
|
|
4884
|
+
const jarResult = spawnSync("jar", ["-xf", join(tempDir, fname)], {
|
|
4678
4885
|
encoding: "utf-8",
|
|
4679
4886
|
cwd: tempDir
|
|
4680
4887
|
});
|
|
@@ -4693,7 +4900,7 @@ export const extractJarArchive = function (jarFile, tempDir) {
|
|
|
4693
4900
|
jarFiles = [join(tempDir, fname)];
|
|
4694
4901
|
}
|
|
4695
4902
|
if (jarFiles && jarFiles.length) {
|
|
4696
|
-
for (
|
|
4903
|
+
for (const jf of jarFiles) {
|
|
4697
4904
|
pomname = jf.replace(".jar", ".pom");
|
|
4698
4905
|
const jarname = basename(jf);
|
|
4699
4906
|
// Ignore test jars
|
|
@@ -4703,7 +4910,7 @@ export const extractJarArchive = function (jarFile, tempDir) {
|
|
|
4703
4910
|
) {
|
|
4704
4911
|
continue;
|
|
4705
4912
|
}
|
|
4706
|
-
|
|
4913
|
+
const manifestDir = join(tempDir, "META-INF");
|
|
4707
4914
|
const manifestFile = join(manifestDir, "MANIFEST.MF");
|
|
4708
4915
|
let jarResult = {
|
|
4709
4916
|
status: 1
|
|
@@ -4732,32 +4939,42 @@ export const extractJarArchive = function (jarFile, tempDir) {
|
|
|
4732
4939
|
jarMetadata["Bundle-Vendor"] ||
|
|
4733
4940
|
jarMetadata["Automatic-Module-Name"] ||
|
|
4734
4941
|
"";
|
|
4942
|
+
let version =
|
|
4943
|
+
jarMetadata["Bundle-Version"] ||
|
|
4944
|
+
jarMetadata["Implementation-Version"] ||
|
|
4945
|
+
jarMetadata["Specification-Version"];
|
|
4946
|
+
if (version && version.includes(" ")) {
|
|
4947
|
+
version = version.split(" ")[0];
|
|
4948
|
+
}
|
|
4735
4949
|
let name = "";
|
|
4950
|
+
// Prefer jar filename to construct name and version
|
|
4951
|
+
if (!name || !version || name === "" || version === "") {
|
|
4952
|
+
const tmpA = jarname.split("-");
|
|
4953
|
+
if (tmpA && tmpA.length > 1) {
|
|
4954
|
+
const lastPart = tmpA[tmpA.length - 1];
|
|
4955
|
+
if (!version || version === "") {
|
|
4956
|
+
version = lastPart.replace(".jar", "");
|
|
4957
|
+
}
|
|
4958
|
+
if (!name || name === "") {
|
|
4959
|
+
name = jarname.replace("-" + lastPart, "") || "";
|
|
4960
|
+
}
|
|
4961
|
+
} else {
|
|
4962
|
+
name = jarname.replace(".jar", "");
|
|
4963
|
+
}
|
|
4964
|
+
}
|
|
4736
4965
|
if (
|
|
4966
|
+
!name.length &&
|
|
4737
4967
|
jarMetadata["Bundle-Name"] &&
|
|
4738
4968
|
!jarMetadata["Bundle-Name"].includes(" ")
|
|
4739
4969
|
) {
|
|
4740
4970
|
name = jarMetadata["Bundle-Name"];
|
|
4741
4971
|
} else if (
|
|
4972
|
+
!name.length &&
|
|
4742
4973
|
jarMetadata["Implementation-Title"] &&
|
|
4743
4974
|
!jarMetadata["Implementation-Title"].includes(" ")
|
|
4744
4975
|
) {
|
|
4745
4976
|
name = jarMetadata["Implementation-Title"];
|
|
4746
4977
|
}
|
|
4747
|
-
let version =
|
|
4748
|
-
jarMetadata["Bundle-Version"] ||
|
|
4749
|
-
jarMetadata["Implementation-Version"] ||
|
|
4750
|
-
jarMetadata["Specification-Version"];
|
|
4751
|
-
if (version && version.includes(" ")) {
|
|
4752
|
-
version = version.split(" ")[0];
|
|
4753
|
-
}
|
|
4754
|
-
if (!name && group) {
|
|
4755
|
-
name = basename(group.replace(/\./g, "/"));
|
|
4756
|
-
if (!group.startsWith("javax")) {
|
|
4757
|
-
group = dirname(group.replace(/\./g, "/"));
|
|
4758
|
-
group = group.replace(/\//g, ".");
|
|
4759
|
-
}
|
|
4760
|
-
}
|
|
4761
4978
|
// Sometimes the group might already contain the name
|
|
4762
4979
|
// Eg: group: org.checkerframework.checker.qual name: checker-qual
|
|
4763
4980
|
if (name && group && !group.startsWith("javax")) {
|
|
@@ -4773,21 +4990,6 @@ export const extractJarArchive = function (jarFile, tempDir) {
|
|
|
4773
4990
|
);
|
|
4774
4991
|
}
|
|
4775
4992
|
}
|
|
4776
|
-
// Fallback to parsing jar filename
|
|
4777
|
-
if (!name || !version || name === "" || version === "") {
|
|
4778
|
-
const tmpA = jarname.split("-");
|
|
4779
|
-
if (tmpA && tmpA.length > 1) {
|
|
4780
|
-
const lastPart = tmpA[tmpA.length - 1];
|
|
4781
|
-
if (!version || version === "") {
|
|
4782
|
-
version = lastPart.replace(".jar", "");
|
|
4783
|
-
}
|
|
4784
|
-
if (!name || name === "") {
|
|
4785
|
-
name = jarname.replace("-" + lastPart, "") || "";
|
|
4786
|
-
}
|
|
4787
|
-
} else {
|
|
4788
|
-
name = jarname.replace(".jar", "");
|
|
4789
|
-
}
|
|
4790
|
-
}
|
|
4791
4993
|
// Patch the group string
|
|
4792
4994
|
for (const aprefix in vendorAliases) {
|
|
4793
4995
|
if (name && name.startsWith(aprefix)) {
|
|
@@ -4796,10 +4998,27 @@ export const extractJarArchive = function (jarFile, tempDir) {
|
|
|
4796
4998
|
}
|
|
4797
4999
|
}
|
|
4798
5000
|
if (name && version) {
|
|
5001
|
+
// If group and name are the same we only need the name
|
|
5002
|
+
if (group == name) {
|
|
5003
|
+
group = "";
|
|
5004
|
+
}
|
|
4799
5005
|
pkgList.push({
|
|
4800
5006
|
group: group === "." ? "" : encodeForPurl(group || "") || "",
|
|
4801
5007
|
name: name ? encodeForPurl(name) : "",
|
|
4802
5008
|
version,
|
|
5009
|
+
evidence: {
|
|
5010
|
+
identity: {
|
|
5011
|
+
field: "purl",
|
|
5012
|
+
confidence: 0.5,
|
|
5013
|
+
methods: [
|
|
5014
|
+
{
|
|
5015
|
+
technique: "filename",
|
|
5016
|
+
confidence: 0.5,
|
|
5017
|
+
value: jarname
|
|
5018
|
+
}
|
|
5019
|
+
]
|
|
5020
|
+
}
|
|
5021
|
+
},
|
|
4803
5022
|
properties: [
|
|
4804
5023
|
{
|
|
4805
5024
|
name: "SrcFile",
|
|
@@ -4841,8 +5060,8 @@ export const extractJarArchive = function (jarFile, tempDir) {
|
|
|
4841
5060
|
export const determineSbtVersion = function (projectPath) {
|
|
4842
5061
|
const buildPropFile = join(projectPath, "project", "build.properties");
|
|
4843
5062
|
if (existsSync(buildPropFile)) {
|
|
4844
|
-
|
|
4845
|
-
|
|
5063
|
+
const properties = propertiesReader(buildPropFile);
|
|
5064
|
+
const property = properties.get("sbt.version");
|
|
4846
5065
|
if (property != null && valid(property)) {
|
|
4847
5066
|
return property;
|
|
4848
5067
|
}
|
|
@@ -4864,7 +5083,7 @@ export const determineSbtVersion = function (projectPath) {
|
|
|
4864
5083
|
*/
|
|
4865
5084
|
export const addPlugin = function (projectPath, plugin) {
|
|
4866
5085
|
const pluginsFile = sbtPluginsPath(projectPath);
|
|
4867
|
-
|
|
5086
|
+
let originalPluginsFile = null;
|
|
4868
5087
|
if (existsSync(pluginsFile)) {
|
|
4869
5088
|
originalPluginsFile = pluginsFile + ".cdxgen";
|
|
4870
5089
|
copyFileSync(pluginsFile, originalPluginsFile, constants.COPYFILE_FICLONE);
|
|
@@ -4997,6 +5216,12 @@ export const getMavenCommand = (srcPath, rootPath) => {
|
|
|
4997
5216
|
let findMavenFile = "mvnw";
|
|
4998
5217
|
if (platform() == "win32") {
|
|
4999
5218
|
findMavenFile = "mvnw.bat";
|
|
5219
|
+
if (
|
|
5220
|
+
!existsSync(join(srcPath, findMavenFile)) &&
|
|
5221
|
+
existsSync(join(srcPath, "mvnw.cmd"))
|
|
5222
|
+
) {
|
|
5223
|
+
findMavenFile = "mvnw.cmd";
|
|
5224
|
+
}
|
|
5000
5225
|
}
|
|
5001
5226
|
|
|
5002
5227
|
if (existsSync(join(srcPath, findMavenFile))) {
|
|
@@ -5071,6 +5296,16 @@ export const executeAtom = (src, args) => {
|
|
|
5071
5296
|
timeout: TIMEOUT_MS,
|
|
5072
5297
|
env
|
|
5073
5298
|
});
|
|
5299
|
+
if (
|
|
5300
|
+
result.stderr &&
|
|
5301
|
+
result.stderr.includes(
|
|
5302
|
+
"has been compiled by a more recent version of the Java Runtime"
|
|
5303
|
+
)
|
|
5304
|
+
) {
|
|
5305
|
+
console.log(
|
|
5306
|
+
"Atom requires Java 17 or above. Please install a suitable version and re-run cdxgen to improve the SBoM accuracy.\nAlternatively, use the cdxgen container image."
|
|
5307
|
+
);
|
|
5308
|
+
}
|
|
5074
5309
|
if (DEBUG_MODE) {
|
|
5075
5310
|
if (result.stdout) {
|
|
5076
5311
|
console.log(result.stdout);
|
|
@@ -5118,17 +5353,62 @@ export const findAppModules = function (src, language) {
|
|
|
5118
5353
|
return retList;
|
|
5119
5354
|
};
|
|
5120
5355
|
|
|
5356
|
+
const flattenDeps = (
|
|
5357
|
+
dependsOn,
|
|
5358
|
+
dependenciesList,
|
|
5359
|
+
pkgList,
|
|
5360
|
+
reqOrSetupFile,
|
|
5361
|
+
t
|
|
5362
|
+
) => {
|
|
5363
|
+
for (const d of t.dependencies) {
|
|
5364
|
+
const pkgRef = `pkg:pypi/${d.name}@${d.version}`
|
|
5365
|
+
.replace(/_/g, "-")
|
|
5366
|
+
.toLowerCase();
|
|
5367
|
+
dependsOn.push(pkgRef);
|
|
5368
|
+
dependenciesList.push({ ref: pkgRef, dependsOn: [] });
|
|
5369
|
+
pkgList.push({
|
|
5370
|
+
name: d.name,
|
|
5371
|
+
version: d.version,
|
|
5372
|
+
properties: [
|
|
5373
|
+
{
|
|
5374
|
+
name: "SrcFile",
|
|
5375
|
+
value: reqOrSetupFile
|
|
5376
|
+
}
|
|
5377
|
+
],
|
|
5378
|
+
evidence: {
|
|
5379
|
+
identity: {
|
|
5380
|
+
field: "purl",
|
|
5381
|
+
confidence: 1,
|
|
5382
|
+
methods: [
|
|
5383
|
+
{
|
|
5384
|
+
technique: "manifest-analysis",
|
|
5385
|
+
confidence: 1,
|
|
5386
|
+
value: reqOrSetupFile
|
|
5387
|
+
}
|
|
5388
|
+
]
|
|
5389
|
+
}
|
|
5390
|
+
}
|
|
5391
|
+
});
|
|
5392
|
+
// Recurse and flatten
|
|
5393
|
+
if (d.dependencies && d.dependencies) {
|
|
5394
|
+
flattenDeps(dependsOn, dependenciesList, pkgList, reqOrSetupFile, d);
|
|
5395
|
+
}
|
|
5396
|
+
}
|
|
5397
|
+
};
|
|
5398
|
+
|
|
5121
5399
|
/**
|
|
5122
|
-
* Execute pip freeze by creating a virtual env in a temp directory
|
|
5400
|
+
* Execute pip freeze by creating a virtual env in a temp directory and construct the dependency tree
|
|
5123
5401
|
*
|
|
5124
5402
|
* @param {string} basePath Base path
|
|
5125
5403
|
* @param {string} reqOrSetupFile Requirements or setup.py file
|
|
5404
|
+
* @param {string} tempVenvDir Temp venv dir
|
|
5126
5405
|
* @returns List of packages from the virtual env
|
|
5127
5406
|
*/
|
|
5128
|
-
export const
|
|
5129
|
-
|
|
5407
|
+
export const getPipFrozenTree = (basePath, reqOrSetupFile, tempVenvDir) => {
|
|
5408
|
+
const pkgList = [];
|
|
5409
|
+
const rootList = [];
|
|
5410
|
+
const dependenciesList = [];
|
|
5130
5411
|
let result = undefined;
|
|
5131
|
-
const tempDir = mkdtempSync(join(tmpdir(), "cdxgen-venv-"));
|
|
5132
5412
|
const env = {
|
|
5133
5413
|
...process.env
|
|
5134
5414
|
};
|
|
@@ -5138,16 +5418,22 @@ export const executePipFreezeInVenv = async (basePath, reqOrSetupFile) => {
|
|
|
5138
5418
|
* By checking the environment variable "VIRTUAL_ENV" we decide whether to create an env or not
|
|
5139
5419
|
*/
|
|
5140
5420
|
if (!process.env.VIRTUAL_ENV) {
|
|
5141
|
-
result = spawnSync(PYTHON_CMD, ["-m", "venv",
|
|
5421
|
+
result = spawnSync(PYTHON_CMD, ["-m", "venv", tempVenvDir]);
|
|
5142
5422
|
if (result.status !== 0 || result.error) {
|
|
5143
5423
|
if (DEBUG_MODE) {
|
|
5144
|
-
console.log(
|
|
5424
|
+
console.log("Virtual env creation has failed");
|
|
5425
|
+
if (!result.stderr) {
|
|
5426
|
+
console.log(
|
|
5427
|
+
"Ensure the virtualenv package is installed using pip. `python -m pip install virtualenv`"
|
|
5428
|
+
);
|
|
5429
|
+
}
|
|
5145
5430
|
}
|
|
5146
5431
|
} else {
|
|
5147
|
-
env.VIRTUAL_ENV =
|
|
5148
|
-
env.PATH = `${join(
|
|
5149
|
-
|
|
5150
|
-
|
|
5432
|
+
env.VIRTUAL_ENV = tempVenvDir;
|
|
5433
|
+
env.PATH = `${join(
|
|
5434
|
+
tempVenvDir,
|
|
5435
|
+
platform() == "win32" ? "Scripts" : "bin"
|
|
5436
|
+
)}${_delimiter}${process.env.PATH || ""}`;
|
|
5151
5437
|
}
|
|
5152
5438
|
}
|
|
5153
5439
|
/**
|
|
@@ -5156,8 +5442,8 @@ export const executePipFreezeInVenv = async (basePath, reqOrSetupFile) => {
|
|
|
5156
5442
|
* This step is accurate but not reproducible since the resulting list could differ based on various factors
|
|
5157
5443
|
* such as the version of python, pip, os, pypi.org availability (and weather?)
|
|
5158
5444
|
*/
|
|
5159
|
-
if (
|
|
5160
|
-
|
|
5445
|
+
if (tempVenvDir === env.VIRTUAL_ENV && reqOrSetupFile) {
|
|
5446
|
+
const pipInstallArgs = [
|
|
5161
5447
|
"-m",
|
|
5162
5448
|
"pip",
|
|
5163
5449
|
"install",
|
|
@@ -5197,6 +5483,7 @@ export const executePipFreezeInVenv = async (basePath, reqOrSetupFile) => {
|
|
|
5197
5483
|
}
|
|
5198
5484
|
if (!versionRelatedError && DEBUG_MODE) {
|
|
5199
5485
|
console.log("args used:", pipInstallArgs);
|
|
5486
|
+
console.log(result.stdout, result.stderr);
|
|
5200
5487
|
console.log(
|
|
5201
5488
|
"Possible build errors detected. The resulting list in the SBoM would therefore be incomplete.\nTry installing any missing build tools or development libraries to improve the accuracy."
|
|
5202
5489
|
);
|
|
@@ -5215,43 +5502,42 @@ export const executePipFreezeInVenv = async (basePath, reqOrSetupFile) => {
|
|
|
5215
5502
|
console.log("- Check if any git submodules have to be initialized.");
|
|
5216
5503
|
}
|
|
5217
5504
|
}
|
|
5505
|
+
}
|
|
5506
|
+
// Bug #375. Attempt pip freeze on existing and new virtual environments
|
|
5507
|
+
if (env.VIRTUAL_ENV && env.VIRTUAL_ENV.length) {
|
|
5218
5508
|
/**
|
|
5219
5509
|
* At this point, the previous attempt to do a pip install might have failed and we might have an unclean virtual environment with an incomplete list
|
|
5220
5510
|
* The position taken by cdxgen is "Some SBoM is better than no SBoM", so we proceed to collecting the dependencies that got installed with pip freeze
|
|
5221
5511
|
*/
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
"-l",
|
|
5227
|
-
"--exclude-editable",
|
|
5228
|
-
"--disable-pip-version-check"
|
|
5229
|
-
];
|
|
5230
|
-
if (
|
|
5231
|
-
!reqOrSetupFile.endsWith("setup.py") &&
|
|
5232
|
-
!reqOrSetupFile.endsWith("pyproject.toml")
|
|
5233
|
-
) {
|
|
5234
|
-
pipFreezeArgs.push("-r");
|
|
5235
|
-
pipFreezeArgs.push(resolve(reqOrSetupFile));
|
|
5512
|
+
if (DEBUG_MODE) {
|
|
5513
|
+
console.log(
|
|
5514
|
+
"About to construct the pip dependency tree. Please wait ..."
|
|
5515
|
+
);
|
|
5236
5516
|
}
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
}
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
const reqData = Buffer.from(result.stdout).toString();
|
|
5247
|
-
const dlist = await parseReqFile(reqData, false);
|
|
5248
|
-
if (dlist && dlist.length) {
|
|
5249
|
-
pkgList = pkgList.concat(dlist);
|
|
5250
|
-
}
|
|
5251
|
-
} else if (result.status !== 0 || result.error) {
|
|
5252
|
-
if (DEBUG_MODE) {
|
|
5253
|
-
console.log(result.stderr, "args used:", pipFreezeArgs);
|
|
5517
|
+
const tree = getTreeWithPlugin(env, PYTHON_CMD, basePath);
|
|
5518
|
+
if (DEBUG_MODE && !tree.length) {
|
|
5519
|
+
console.log(
|
|
5520
|
+
"Dependency tree generation has failed. Please check for any errors or version incompatibilities reported in the logs."
|
|
5521
|
+
);
|
|
5522
|
+
}
|
|
5523
|
+
for (const t of tree) {
|
|
5524
|
+
if (!t.version.length) {
|
|
5525
|
+
continue;
|
|
5254
5526
|
}
|
|
5527
|
+
pkgList.push({
|
|
5528
|
+
name: t.name.replace(/_/g, "-"),
|
|
5529
|
+
version: t.version
|
|
5530
|
+
});
|
|
5531
|
+
rootList.push({
|
|
5532
|
+
name: t.name.replace(/_/g, "-"),
|
|
5533
|
+
version: t.version
|
|
5534
|
+
});
|
|
5535
|
+
const dependsOn = [];
|
|
5536
|
+
flattenDeps(dependsOn, dependenciesList, pkgList, reqOrSetupFile, t);
|
|
5537
|
+
dependenciesList.push({
|
|
5538
|
+
ref: `pkg:pypi/${t.name}@${t.version}`.replace(/_/g, "-").toLowerCase(),
|
|
5539
|
+
dependsOn
|
|
5540
|
+
});
|
|
5255
5541
|
}
|
|
5256
5542
|
} else {
|
|
5257
5543
|
if (DEBUG_MODE) {
|
|
@@ -5260,11 +5546,11 @@ export const executePipFreezeInVenv = async (basePath, reqOrSetupFile) => {
|
|
|
5260
5546
|
);
|
|
5261
5547
|
}
|
|
5262
5548
|
}
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5549
|
+
return {
|
|
5550
|
+
pkgList,
|
|
5551
|
+
rootList,
|
|
5552
|
+
dependenciesList
|
|
5553
|
+
};
|
|
5268
5554
|
};
|
|
5269
5555
|
|
|
5270
5556
|
// taken from a very old package https://github.com/keithamus/parse-packagejson-name/blob/master/index.js
|