@cyclonedx/cdxgen 8.5.3 → 9.0.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/utils.js CHANGED
@@ -1,22 +1,66 @@
1
- const glob = require("glob");
2
- const os = require("os");
3
- const path = require("path");
4
- const parsePackageJsonName = require("parse-packagejson-name");
5
- const fs = require("fs");
6
- const got = require("got");
7
- const convert = require("xml-js");
8
- const licenseMapping = require("./lic-mapping.json");
9
- const vendorAliases = require("./vendor-alias.json");
10
- const spdxLicenses = require("./spdx-licenses.json");
11
- const knownLicenses = require("./known-licenses.json");
12
- const cheerio = require("cheerio");
13
- const yaml = require("js-yaml");
14
- const { spawnSync } = require("child_process");
15
- const propertiesReader = require("properties-reader");
16
- const semver = require("semver");
17
- const StreamZip = require("node-stream-zip");
18
- const ednDataLib = require("edn-data");
19
- const { PackageURL } = require("packageurl-js");
1
+ import { globSync } from "glob";
2
+ import { tmpdir, platform, freemem } from "node:os";
3
+ import {
4
+ dirname,
5
+ sep as _sep,
6
+ basename,
7
+ join,
8
+ resolve,
9
+ delimiter as _delimiter
10
+ } from "node:path";
11
+ import {
12
+ existsSync,
13
+ readFileSync,
14
+ mkdtempSync,
15
+ rmSync,
16
+ copyFileSync,
17
+ constants,
18
+ writeFileSync,
19
+ unlinkSync,
20
+ chmodSync
21
+ } from "node:fs";
22
+ import got from "got";
23
+ import { xml2js } from "xml-js";
24
+ import { fileURLToPath } from "node:url";
25
+ let url = import.meta.url;
26
+ if (!url.startsWith("file://")) {
27
+ url = new URL(`file://${import.meta.url}`).toString();
28
+ }
29
+ const dirName = import.meta ? dirname(fileURLToPath(url)) : __dirname;
30
+
31
+ const licenseMapping = JSON.parse(
32
+ readFileSync(join(dirName, "data", "lic-mapping.json"))
33
+ );
34
+ const vendorAliases = JSON.parse(
35
+ readFileSync(join(dirName, "data", "vendor-alias.json"))
36
+ );
37
+ const spdxLicenses = JSON.parse(
38
+ readFileSync(join(dirName, "data", "spdx-licenses.json"))
39
+ );
40
+ const knownLicenses = JSON.parse(
41
+ readFileSync(join(dirName, "data", "known-licenses.json"))
42
+ );
43
+ import { load } from "cheerio";
44
+ import { load as _load } from "js-yaml";
45
+ import { spawnSync } from "node:child_process";
46
+ import propertiesReader from "properties-reader";
47
+ import { satisfies, coerce, maxSatisfying, clean, valid } from "semver";
48
+ import StreamZip from "node-stream-zip";
49
+ import { parseEDNString } from "edn-data";
50
+ import { PackageURL } from "packageurl-js";
51
+
52
+ const selfPJson = JSON.parse(readFileSync(join(dirName, "package.json")));
53
+ const _version = selfPJson.version;
54
+
55
+ // Refer to contrib/py-modules.py for a script to generate this list
56
+ // The script needs to be used once every few months to update this list
57
+ const PYTHON_STD_MODULES = JSON.parse(
58
+ readFileSync(join(dirName, "data", "python-stdlib.json"))
59
+ );
60
+ // Mapping between modules and package names
61
+ const PYPI_MODULE_PACKAGE_MAPPING = JSON.parse(
62
+ readFileSync(join(dirName, "data", "pypi-pkg-aliases.json"))
63
+ );
20
64
 
21
65
  // Debug mode flag
22
66
  const DEBUG_MODE =
@@ -24,14 +68,16 @@ const DEBUG_MODE =
24
68
  process.env.SCAN_DEBUG_MODE === "debug" ||
25
69
  process.env.SHIFTLEFT_LOGGING_LEVEL === "debug";
26
70
 
71
+ // Timeout milliseconds. Default 10 mins
72
+ const TIMEOUT_MS = parseInt(process.env.CDXGEN_TIMEOUT_MS) || 10 * 60 * 1000;
73
+
27
74
  // Metadata cache
28
75
  let metadata_cache = {};
29
76
 
30
77
  // Whether test scope shall be included for java/maven projects; default, if unset shall be 'true'
31
- const includeMavenTestScope =
78
+ export const includeMavenTestScope =
32
79
  !process.env.CDX_MAVEN_INCLUDE_TEST_SCOPE ||
33
80
  ["true", "1"].includes(process.env.CDX_MAVEN_INCLUDE_TEST_SCOPE);
34
- exports.includeMavenTestScope = includeMavenTestScope;
35
81
 
36
82
  // Whether license information should be fetched
37
83
  const fetchLicenses =
@@ -40,13 +86,25 @@ const fetchLicenses =
40
86
 
41
87
  const MAX_LICENSE_ID_LENGTH = 100;
42
88
 
89
+ let PYTHON_CMD = "python";
90
+ if (process.env.PYTHON_CMD) {
91
+ PYTHON_CMD = process.env.PYTHON_CMD;
92
+ }
93
+
94
+ // Custom user-agent for cdxgen
95
+ const cdxgenAgent = got.extend({
96
+ headers: {
97
+ "user-agent": `@CycloneDX/cdxgen ${_version}`
98
+ }
99
+ });
100
+
43
101
  /**
44
102
  * Method to get files matching a pattern
45
103
  *
46
104
  * @param {string} dirPath Root directory for search
47
105
  * @param {string} pattern Glob pattern (eg: *.gradle)
48
106
  */
49
- const getAllFiles = function (dirPath, pattern) {
107
+ export const getAllFiles = function (dirPath, pattern) {
50
108
  try {
51
109
  const ignoreList = [
52
110
  "**/.hg/**",
@@ -60,9 +118,8 @@ const getAllFiles = function (dirPath, pattern) {
60
118
  if (!pattern.includes("package.json")) {
61
119
  ignoreList.push("**/node_modules/**");
62
120
  }
63
- return glob.sync(pattern, {
121
+ return globSync(pattern, {
64
122
  cwd: dirPath,
65
- silent: true,
66
123
  absolute: true,
67
124
  nocase: true,
68
125
  nodir: true,
@@ -78,7 +135,6 @@ const getAllFiles = function (dirPath, pattern) {
78
135
  return [];
79
136
  }
80
137
  };
81
- exports.getAllFiles = getAllFiles;
82
138
 
83
139
  const toBase64 = (hexString) => {
84
140
  return Buffer.from(hexString, "hex").toString("base64");
@@ -90,7 +146,7 @@ const toBase64 = (hexString) => {
90
146
  * and url of the license object, otherwise, set the 'name' of the license
91
147
  * object.
92
148
  */
93
- function getLicenses(pkg, format = "xml") {
149
+ export function getLicenses(pkg, format = "xml") {
94
150
  let license = pkg.license && (pkg.license.type || pkg.license);
95
151
  if (license) {
96
152
  if (!Array.isArray(license)) {
@@ -132,14 +188,13 @@ function getLicenses(pkg, format = "xml") {
132
188
  }
133
189
  return [];
134
190
  }
135
- exports.getLicenses = getLicenses;
136
191
 
137
192
  /**
138
193
  * Tries to find a file containing the license text based on commonly
139
194
  * used naming and content types. If a candidate file is found, add
140
195
  * the text to the license text object and stop.
141
196
  */
142
- function addLicenseText(pkg, l, licenseContent, format = "xml") {
197
+ export function addLicenseText(pkg, l, licenseContent, format = "xml") {
143
198
  let licenseFilenames = [
144
199
  "LICENSE",
145
200
  "License",
@@ -165,7 +220,7 @@ function addLicenseText(pkg, l, licenseContent, format = "xml") {
165
220
  licenseContentTypes
166
221
  )) {
167
222
  let licenseFilepath = `${pkg.realPath}/${licenseFilename}${licenseName}${fileExtension}`;
168
- if (fs.existsSync(licenseFilepath)) {
223
+ if (existsSync(licenseFilepath)) {
169
224
  licenseContent.text = readLicenseText(
170
225
  licenseFilepath,
171
226
  licenseContentType,
@@ -182,8 +237,12 @@ function addLicenseText(pkg, l, licenseContent, format = "xml") {
182
237
  * Read the file from the given path to the license text object and includes
183
238
  * content-type attribute, if not default. Returns the license text object.
184
239
  */
185
- function readLicenseText(licenseFilepath, licenseContentType, format = "xml") {
186
- let licenseText = fs.readFileSync(licenseFilepath, "utf8");
240
+ export function readLicenseText(
241
+ licenseFilepath,
242
+ licenseContentType,
243
+ format = "xml"
244
+ ) {
245
+ let licenseText = readFileSync(licenseFilepath, "utf8");
187
246
  if (licenseText) {
188
247
  if (format === "xml") {
189
248
  let licenseContentText = { "#cdata": licenseText };
@@ -207,7 +266,7 @@ function readLicenseText(licenseFilepath, licenseContentType, format = "xml") {
207
266
  *
208
267
  * @param {Array} pkgList Package list
209
268
  */
210
- const getNpmMetadata = async function (pkgList) {
269
+ export const getNpmMetadata = async function (pkgList) {
211
270
  const NPM_URL = "https://registry.npmjs.org/";
212
271
  const cdepList = [];
213
272
  for (const p of pkgList) {
@@ -224,7 +283,7 @@ const getNpmMetadata = async function (pkgList) {
224
283
  if (metadata_cache[key]) {
225
284
  body = metadata_cache[key];
226
285
  } else {
227
- const res = await got.get(NPM_URL + key, {
286
+ const res = await cdxgenAgent.get(NPM_URL + key, {
228
287
  responseType: "json"
229
288
  });
230
289
  body = res.body;
@@ -248,7 +307,6 @@ const getNpmMetadata = async function (pkgList) {
248
307
  }
249
308
  return cdepList;
250
309
  };
251
- exports.getNpmMetadata = getNpmMetadata;
252
310
 
253
311
  const _getDepPkgList = async function (
254
312
  pkgLockFile,
@@ -349,11 +407,11 @@ const _getDepPkgList = async function (
349
407
  *
350
408
  * @param {string} pkgJsonFile package.json file
351
409
  */
352
- const parsePkgJson = async (pkgJsonFile) => {
410
+ export const parsePkgJson = async (pkgJsonFile) => {
353
411
  const pkgList = [];
354
- if (fs.existsSync(pkgJsonFile)) {
412
+ if (existsSync(pkgJsonFile)) {
355
413
  try {
356
- const pkgData = JSON.parse(fs.readFileSync(pkgJsonFile, "utf8"));
414
+ const pkgData = JSON.parse(readFileSync(pkgJsonFile, "utf8"));
357
415
  const pkgIdentifier = parsePackageJsonName(pkgData.name);
358
416
  pkgList.push({
359
417
  name: pkgIdentifier.fullName || pkgData.name,
@@ -380,20 +438,19 @@ const parsePkgJson = async (pkgJsonFile) => {
380
438
  }
381
439
  return pkgList;
382
440
  };
383
- exports.parsePkgJson = parsePkgJson;
384
441
 
385
442
  /**
386
443
  * Parse nodejs package lock file
387
444
  *
388
445
  * @param {string} pkgLockFile package-lock.json file
389
446
  */
390
- const parsePkgLock = async (pkgLockFile) => {
447
+ export const parsePkgLock = async (pkgLockFile) => {
391
448
  let pkgList = [];
392
449
  let dependenciesList = [];
393
450
  let depKeys = {};
394
451
  let rootPkg = {};
395
- if (fs.existsSync(pkgLockFile)) {
396
- const lockData = JSON.parse(fs.readFileSync(pkgLockFile, "utf8"));
452
+ if (existsSync(pkgLockFile)) {
453
+ const lockData = JSON.parse(readFileSync(pkgLockFile, "utf8"));
397
454
  rootPkg.name = lockData.name || "";
398
455
  // lockfile v2 onwards
399
456
  if (lockData.name && lockData.packages && lockData.packages[""]) {
@@ -405,8 +462,8 @@ const parsePkgLock = async (pkgLockFile) => {
405
462
  type: "application"
406
463
  };
407
464
  } else if (lockData.lockfileVersion === 1) {
408
- let dirName = path.dirname(pkgLockFile);
409
- const tmpA = dirName.split(path.sep);
465
+ let dirName = dirname(pkgLockFile);
466
+ const tmpA = dirName.split(_sep);
410
467
  dirName = tmpA[tmpA.length - 1];
411
468
  // v1 lock file
412
469
  rootPkg = {
@@ -491,7 +548,6 @@ const parsePkgLock = async (pkgLockFile) => {
491
548
  dependenciesList
492
549
  };
493
550
  };
494
- exports.parsePkgLock = parsePkgLock;
495
551
 
496
552
  /**
497
553
  * Given a lock file this method would return an Object with the identiy as the key and parsed name and value
@@ -501,7 +557,7 @@ exports.parsePkgLock = parsePkgLock;
501
557
  *
502
558
  * @param {string} lockData Yarn Lockfile data
503
559
  */
504
- const yarnLockToIdentMap = function (lockData) {
560
+ export const yarnLockToIdentMap = function (lockData) {
505
561
  const identMap = {};
506
562
  let currentIdents = [];
507
563
  lockData.split("\n").forEach((l) => {
@@ -544,19 +600,18 @@ const yarnLockToIdentMap = function (lockData) {
544
600
  });
545
601
  return identMap;
546
602
  };
547
- exports.yarnLockToIdentMap = yarnLockToIdentMap;
548
603
 
549
604
  /**
550
605
  * Parse nodejs yarn lock file
551
606
  *
552
607
  * @param {string} yarnLockFile yarn.lock file
553
608
  */
554
- const parseYarnLock = async function (yarnLockFile) {
609
+ export const parseYarnLock = async function (yarnLockFile) {
555
610
  let pkgList = [];
556
611
  const dependenciesList = [];
557
612
  const depKeys = {};
558
- if (fs.existsSync(yarnLockFile)) {
559
- const lockData = fs.readFileSync(yarnLockFile, "utf8");
613
+ if (existsSync(yarnLockFile)) {
614
+ const lockData = readFileSync(yarnLockFile, "utf8");
560
615
  let name = "";
561
616
  let group = "";
562
617
  let version = "";
@@ -700,17 +755,16 @@ const parseYarnLock = async function (yarnLockFile) {
700
755
  dependenciesList
701
756
  };
702
757
  };
703
- exports.parseYarnLock = parseYarnLock;
704
758
 
705
759
  /**
706
760
  * Parse nodejs shrinkwrap deps file
707
761
  *
708
762
  * @param {string} swFile shrinkwrap-deps.json file
709
763
  */
710
- const parseNodeShrinkwrap = async function (swFile) {
764
+ export const parseNodeShrinkwrap = async function (swFile) {
711
765
  const pkgList = [];
712
- if (fs.existsSync(swFile)) {
713
- const lockData = JSON.parse(fs.readFileSync(swFile, "utf8"));
766
+ if (existsSync(swFile)) {
767
+ const lockData = JSON.parse(readFileSync(swFile, "utf8"));
714
768
  const pkgKeys = Object.keys(lockData);
715
769
  for (var k in pkgKeys) {
716
770
  const fullName = pkgKeys[k];
@@ -760,14 +814,13 @@ const parseNodeShrinkwrap = async function (swFile) {
760
814
  }
761
815
  return pkgList;
762
816
  };
763
- exports.parseNodeShrinkwrap = parseNodeShrinkwrap;
764
817
 
765
818
  /**
766
819
  * Parse nodejs pnpm lock file
767
820
  *
768
821
  * @param {string} pnpmLock pnpm-lock.yaml file
769
822
  */
770
- const parsePnpmLock = async function (pnpmLock, parentComponent = null) {
823
+ export const parsePnpmLock = async function (pnpmLock, parentComponent = null) {
771
824
  let pkgList = [];
772
825
  const dependenciesList = [];
773
826
  let ppurl = "";
@@ -783,9 +836,9 @@ const parsePnpmLock = async function (pnpmLock, parentComponent = null) {
783
836
  null
784
837
  ).toString();
785
838
  }
786
- if (fs.existsSync(pnpmLock)) {
787
- const lockData = fs.readFileSync(pnpmLock, "utf8");
788
- const yamlObj = yaml.load(lockData);
839
+ if (existsSync(pnpmLock)) {
840
+ const lockData = readFileSync(pnpmLock, "utf8");
841
+ const yamlObj = _load(lockData);
789
842
  if (!yamlObj) {
790
843
  return {};
791
844
  }
@@ -922,18 +975,17 @@ const parsePnpmLock = async function (pnpmLock, parentComponent = null) {
922
975
  dependenciesList
923
976
  };
924
977
  };
925
- exports.parsePnpmLock = parsePnpmLock;
926
978
 
927
979
  /**
928
980
  * Parse bower json file
929
981
  *
930
982
  * @param {string} bowerJsonFile bower.json file
931
983
  */
932
- const parseBowerJson = async (bowerJsonFile) => {
984
+ export const parseBowerJson = async (bowerJsonFile) => {
933
985
  const pkgList = [];
934
- if (fs.existsSync(bowerJsonFile)) {
986
+ if (existsSync(bowerJsonFile)) {
935
987
  try {
936
- const pkgData = JSON.parse(fs.readFileSync(bowerJsonFile, "utf8"));
988
+ const pkgData = JSON.parse(readFileSync(bowerJsonFile, "utf8"));
937
989
  const pkgIdentifier = parsePackageJsonName(pkgData.name);
938
990
  pkgList.push({
939
991
  name: pkgIdentifier.fullName || pkgData.name,
@@ -962,18 +1014,17 @@ const parseBowerJson = async (bowerJsonFile) => {
962
1014
  }
963
1015
  return pkgList;
964
1016
  };
965
- exports.parseBowerJson = parseBowerJson;
966
1017
 
967
1018
  /**
968
1019
  * Parse minified js file
969
1020
  *
970
1021
  * @param {string} minJsFile min.js file
971
1022
  */
972
- const parseMinJs = async (minJsFile) => {
1023
+ export const parseMinJs = async (minJsFile) => {
973
1024
  const pkgList = [];
974
- if (fs.existsSync(minJsFile)) {
1025
+ if (existsSync(minJsFile)) {
975
1026
  try {
976
- const rawData = fs.readFileSync(minJsFile, { encoding: "utf-8" });
1027
+ const rawData = readFileSync(minJsFile, { encoding: "utf-8" });
977
1028
  const tmpA = rawData.split("\n");
978
1029
  tmpA.forEach((l) => {
979
1030
  if ((l.startsWith("/*!") || l.startsWith(" * ")) && l.length < 500) {
@@ -1036,17 +1087,16 @@ const parseMinJs = async (minJsFile) => {
1036
1087
  }
1037
1088
  return pkgList;
1038
1089
  };
1039
- exports.parseMinJs = parseMinJs;
1040
1090
 
1041
1091
  /**
1042
1092
  * Parse pom file
1043
1093
  *
1044
1094
  * @param {string} pom file to parse
1045
1095
  */
1046
- const parsePom = function (pomFile) {
1096
+ export const parsePom = function (pomFile) {
1047
1097
  const deps = [];
1048
- const xmlData = fs.readFileSync(pomFile);
1049
- const project = convert.xml2js(xmlData, {
1098
+ const xmlData = readFileSync(pomFile);
1099
+ const project = xml2js(xmlData, {
1050
1100
  compact: true,
1051
1101
  spaces: 4,
1052
1102
  textKey: "_",
@@ -1084,13 +1134,12 @@ const parsePom = function (pomFile) {
1084
1134
  }
1085
1135
  return deps;
1086
1136
  };
1087
- exports.parsePom = parsePom;
1088
1137
 
1089
1138
  /**
1090
1139
  * Parse maven tree output
1091
1140
  * @param {string} rawOutput Raw string output
1092
1141
  */
1093
- const parseMavenTree = function (rawOutput) {
1142
+ export const parseMavenTree = function (rawOutput) {
1094
1143
  if (!rawOutput) {
1095
1144
  return {};
1096
1145
  }
@@ -1176,7 +1225,6 @@ const parseMavenTree = function (rawOutput) {
1176
1225
  dependenciesList
1177
1226
  };
1178
1227
  };
1179
- exports.parseMavenTree = parseMavenTree;
1180
1228
 
1181
1229
  /**
1182
1230
  * Parse gradle dependencies output
@@ -1185,7 +1233,7 @@ exports.parseMavenTree = parseMavenTree;
1185
1233
  * @param {string} rootProjectName Root project name
1186
1234
  * @param {string} rootProjectVersion Root project version
1187
1235
  */
1188
- const parseGradleDep = function (
1236
+ export const parseGradleDep = function (
1189
1237
  rawOutput,
1190
1238
  rootProjectGroup = "",
1191
1239
  rootProjectName = "root",
@@ -1373,13 +1421,12 @@ const parseGradleDep = function (
1373
1421
  }
1374
1422
  return {};
1375
1423
  };
1376
- exports.parseGradleDep = parseGradleDep;
1377
1424
 
1378
1425
  /**
1379
1426
  * Parse clojure cli dependencies output
1380
1427
  * @param {string} rawOutput Raw string output
1381
1428
  */
1382
- const parseCljDep = function (rawOutput) {
1429
+ export const parseCljDep = function (rawOutput) {
1383
1430
  if (typeof rawOutput === "string") {
1384
1431
  const deps = [];
1385
1432
  const keys_cache = {};
@@ -1392,11 +1439,11 @@ const parseCljDep = function (rawOutput) {
1392
1439
  }
1393
1440
  const tmpArr = l.split(" ");
1394
1441
  if (tmpArr.length == 2) {
1395
- let group = path.dirname(tmpArr[0]);
1442
+ let group = dirname(tmpArr[0]);
1396
1443
  if (group === ".") {
1397
1444
  group = "";
1398
1445
  }
1399
- const name = path.basename(tmpArr[0]);
1446
+ const name = basename(tmpArr[0]);
1400
1447
  const version = tmpArr[1];
1401
1448
  const cacheKey = group + "-" + name + "-" + version;
1402
1449
  if (!keys_cache[cacheKey]) {
@@ -1414,38 +1461,36 @@ const parseCljDep = function (rawOutput) {
1414
1461
  }
1415
1462
  return [];
1416
1463
  };
1417
- exports.parseCljDep = parseCljDep;
1418
1464
 
1419
1465
  /**
1420
1466
  * Parse lein dependency tree output
1421
1467
  * @param {string} rawOutput Raw string output
1422
1468
  */
1423
- const parseLeinDep = function (rawOutput) {
1469
+ export const parseLeinDep = function (rawOutput) {
1424
1470
  if (typeof rawOutput === "string") {
1425
1471
  const deps = [];
1426
1472
  const keys_cache = {};
1427
1473
  if (rawOutput.includes("{[") && !rawOutput.startsWith("{[")) {
1428
1474
  rawOutput = "{[" + rawOutput.split("{[")[1];
1429
1475
  }
1430
- const ednData = ednDataLib.parseEDNString(rawOutput);
1476
+ const ednData = parseEDNString(rawOutput);
1431
1477
  return parseLeinMap(ednData, keys_cache, deps);
1432
1478
  }
1433
1479
  return [];
1434
1480
  };
1435
- exports.parseLeinDep = parseLeinDep;
1436
1481
 
1437
- const parseLeinMap = function (node, keys_cache, deps) {
1482
+ export const parseLeinMap = function (node, keys_cache, deps) {
1438
1483
  if (node["map"]) {
1439
1484
  for (let n of node["map"]) {
1440
1485
  if (n.length === 2) {
1441
1486
  const rootNode = n[0];
1442
1487
  let psym = rootNode[0].sym;
1443
1488
  let version = rootNode[1];
1444
- let group = path.dirname(psym);
1489
+ let group = dirname(psym);
1445
1490
  if (group === ".") {
1446
1491
  group = "";
1447
1492
  }
1448
- let name = path.basename(psym);
1493
+ let name = basename(psym);
1449
1494
  let cacheKey = group + "-" + name + "-" + version;
1450
1495
  if (!keys_cache[cacheKey]) {
1451
1496
  keys_cache[cacheKey] = true;
@@ -1459,14 +1504,13 @@ const parseLeinMap = function (node, keys_cache, deps) {
1459
1504
  }
1460
1505
  return deps;
1461
1506
  };
1462
- exports.parseLeinMap = parseLeinMap;
1463
1507
 
1464
1508
  /**
1465
1509
  * Parse gradle projects output
1466
1510
  *
1467
1511
  * @param {string} rawOutput Raw string output
1468
1512
  */
1469
- const parseGradleProjects = function (rawOutput) {
1513
+ export const parseGradleProjects = function (rawOutput) {
1470
1514
  let rootProject = "root";
1471
1515
  const projects = new Set();
1472
1516
  if (typeof rawOutput === "string") {
@@ -1502,14 +1546,13 @@ const parseGradleProjects = function (rawOutput) {
1502
1546
  projects: Array.from(projects)
1503
1547
  };
1504
1548
  };
1505
- exports.parseGradleProjects = parseGradleProjects;
1506
1549
 
1507
1550
  /**
1508
1551
  * Parse gradle properties output
1509
1552
  *
1510
1553
  * @param {string} rawOutput Raw string output
1511
1554
  */
1512
- const parseGradleProperties = function (rawOutput) {
1555
+ export const parseGradleProperties = function (rawOutput) {
1513
1556
  let rootProject = "root";
1514
1557
  let projects = new Set();
1515
1558
  const metadata = { group: "", version: "latest", properties: [] };
@@ -1545,7 +1588,6 @@ const parseGradleProperties = function (rawOutput) {
1545
1588
  metadata
1546
1589
  };
1547
1590
  };
1548
- exports.parseGradleProperties = parseGradleProperties;
1549
1591
 
1550
1592
  /**
1551
1593
  * Execute gradle properties command and return parsed output
@@ -1554,7 +1596,7 @@ exports.parseGradleProperties = parseGradleProperties;
1554
1596
  * @param {string} rootPath Root directory
1555
1597
  * @param {string} subProject Sub project name
1556
1598
  */
1557
- const executeGradleProperties = function (dir, rootPath, subProject) {
1599
+ export const executeGradleProperties = function (dir, rootPath, subProject) {
1558
1600
  const defaultProps = {
1559
1601
  rootProject: subProject,
1560
1602
  projects: [],
@@ -1609,13 +1651,12 @@ const executeGradleProperties = function (dir, rootPath, subProject) {
1609
1651
  }
1610
1652
  return {};
1611
1653
  };
1612
- exports.executeGradleProperties = executeGradleProperties;
1613
1654
 
1614
1655
  /**
1615
1656
  * Parse bazel skyframe state output
1616
1657
  * @param {string} rawOutput Raw string output
1617
1658
  */
1618
- const parseBazelSkyframe = function (rawOutput) {
1659
+ export const parseBazelSkyframe = function (rawOutput) {
1619
1660
  if (typeof rawOutput === "string") {
1620
1661
  const deps = [];
1621
1662
  const keys_cache = {};
@@ -1666,13 +1707,12 @@ const parseBazelSkyframe = function (rawOutput) {
1666
1707
  }
1667
1708
  return [];
1668
1709
  };
1669
- exports.parseBazelSkyframe = parseBazelSkyframe;
1670
1710
 
1671
1711
  /**
1672
1712
  * Parse bazel BUILD file
1673
1713
  * @param {string} rawOutput Raw string output
1674
1714
  */
1675
- const parseBazelBuild = function (rawOutput) {
1715
+ export const parseBazelBuild = function (rawOutput) {
1676
1716
  if (typeof rawOutput === "string") {
1677
1717
  const projs = [];
1678
1718
  const tmpA = rawOutput.split("\n");
@@ -1688,12 +1728,11 @@ const parseBazelBuild = function (rawOutput) {
1688
1728
  }
1689
1729
  return [];
1690
1730
  };
1691
- exports.parseBazelBuild = parseBazelBuild;
1692
1731
 
1693
1732
  /**
1694
1733
  * Parse dependencies in Key:Value format
1695
1734
  */
1696
- const parseKVDep = function (rawOutput) {
1735
+ export const parseKVDep = function (rawOutput) {
1697
1736
  if (typeof rawOutput === "string") {
1698
1737
  const deps = [];
1699
1738
  rawOutput.split("\n").forEach((l) => {
@@ -1718,14 +1757,13 @@ const parseKVDep = function (rawOutput) {
1718
1757
  }
1719
1758
  return [];
1720
1759
  };
1721
- exports.parseKVDep = parseKVDep;
1722
1760
 
1723
1761
  /**
1724
1762
  * Method to find the spdx license id from name
1725
1763
  *
1726
1764
  * @param {string} name License full name
1727
1765
  */
1728
- const findLicenseId = function (name) {
1766
+ export const findLicenseId = function (name) {
1729
1767
  for (let l of licenseMapping) {
1730
1768
  if (l.names.includes(name)) {
1731
1769
  return l.exp;
@@ -1735,14 +1773,13 @@ const findLicenseId = function (name) {
1735
1773
  ? guessLicenseId(name)
1736
1774
  : name;
1737
1775
  };
1738
- exports.findLicenseId = findLicenseId;
1739
1776
 
1740
1777
  /**
1741
1778
  * Method to guess the spdx license id from license contents
1742
1779
  *
1743
1780
  * @param {string} name License file contents
1744
1781
  */
1745
- const guessLicenseId = function (content) {
1782
+ export const guessLicenseId = function (content) {
1746
1783
  content = content.replace(/\n/g, " ");
1747
1784
  for (let l of licenseMapping) {
1748
1785
  for (let j in l.names) {
@@ -1753,14 +1790,13 @@ const guessLicenseId = function (content) {
1753
1790
  }
1754
1791
  return undefined;
1755
1792
  };
1756
- exports.guessLicenseId = guessLicenseId;
1757
1793
 
1758
1794
  /**
1759
1795
  * Method to retrieve metadata for maven packages by querying maven central
1760
1796
  *
1761
1797
  * @param {Array} pkgList Package list
1762
1798
  */
1763
- const getMvnMetadata = async function (pkgList) {
1799
+ export const getMvnMetadata = async function (pkgList) {
1764
1800
  const MAVEN_CENTRAL_URL = "https://repo1.maven.org/maven2/";
1765
1801
  const ANDROID_MAVEN = "https://maven.google.com/";
1766
1802
  const cdepList = [];
@@ -1803,8 +1839,8 @@ const getMvnMetadata = async function (pkgList) {
1803
1839
  if (DEBUG_MODE) {
1804
1840
  console.log(`Querying ${fullUrl}`);
1805
1841
  }
1806
- const res = await got.get(fullUrl);
1807
- const bodyJson = convert.xml2js(res.body, {
1842
+ const res = await cdxgenAgent.get(fullUrl);
1843
+ const bodyJson = xml2js(res.body, {
1808
1844
  compact: true,
1809
1845
  spaces: 4,
1810
1846
  textKey: "_",
@@ -1845,14 +1881,13 @@ const getMvnMetadata = async function (pkgList) {
1845
1881
  }
1846
1882
  return cdepList;
1847
1883
  };
1848
- exports.getMvnMetadata = getMvnMetadata;
1849
1884
 
1850
1885
  /**
1851
1886
  * Method to parse python requires_dist attribute found in pypi setup.py
1852
1887
  *
1853
1888
  * @param requires_dist string
1854
1889
  */
1855
- const parsePyRequiresDist = function (dist_string) {
1890
+ export const parsePyRequiresDist = function (dist_string) {
1856
1891
  if (!dist_string) {
1857
1892
  return undefined;
1858
1893
  }
@@ -1873,7 +1908,25 @@ const parsePyRequiresDist = function (dist_string) {
1873
1908
  version
1874
1909
  };
1875
1910
  };
1876
- exports.parsePyRequiresDist = parsePyRequiresDist;
1911
+
1912
+ /**
1913
+ * Method to mimic pip version solver using node-semver
1914
+ *
1915
+ * @param {Array} versionsList List of version numbers available
1916
+ * @param {*} versionSpecifiers pip version specifier
1917
+ */
1918
+ export const guessPypiMatchingVersion = (versionsList, versionSpecifiers) => {
1919
+ versionSpecifiers = versionSpecifiers.replace(/,/g, " ").split(";")[0];
1920
+ // Iterate in the reverse order
1921
+ for (let i = versionsList.length - 1; i > 0; i--) {
1922
+ let rv = versionsList[i];
1923
+ if (satisfies(coerce(rv), versionSpecifiers, true)) {
1924
+ return rv;
1925
+ }
1926
+ }
1927
+ // Let's try to clean and have another go
1928
+ return maxSatisfying(versionsList, clean(versionSpecifiers, { loose: true }));
1929
+ };
1877
1930
 
1878
1931
  /**
1879
1932
  * Method to retrieve metadata for python packages by querying pypi
@@ -1881,7 +1934,7 @@ exports.parsePyRequiresDist = parsePyRequiresDist;
1881
1934
  * @param {Array} pkgList Package list
1882
1935
  * @param {Boolean} fetchDepsInfo Fetch dependencies info from pypi
1883
1936
  */
1884
- const getPyMetadata = async function (pkgList, fetchDepsInfo) {
1937
+ export const getPyMetadata = async function (pkgList, fetchDepsInfo) {
1885
1938
  if (!fetchLicenses && !fetchDepsInfo) {
1886
1939
  return pkgList;
1887
1940
  }
@@ -1892,7 +1945,8 @@ const getPyMetadata = async function (pkgList, fetchDepsInfo) {
1892
1945
  continue;
1893
1946
  }
1894
1947
  try {
1895
- if (p.name.includes("https")) {
1948
+ // If the package name has a url or already includes license and version skip it
1949
+ if (p.name.includes("https") || (p.license && p.version)) {
1896
1950
  cdepList.push(p);
1897
1951
  continue;
1898
1952
  }
@@ -1900,10 +1954,22 @@ const getPyMetadata = async function (pkgList, fetchDepsInfo) {
1900
1954
  if (p.name.includes("[")) {
1901
1955
  p.name = p.name.split("[")[0];
1902
1956
  }
1903
- const res = await got.get(PYPI_URL + p.name + "/json", {
1957
+ const res = await cdxgenAgent.get(PYPI_URL + p.name + "/json", {
1904
1958
  responseType: "json"
1905
1959
  });
1906
1960
  const body = res.body;
1961
+ if (body.info.author && body.info.author.trim() !== "") {
1962
+ if (body.info.author_email && body.info.author_email.trim() !== "") {
1963
+ p.author = `${body.info.author.trim()} <${body.info.author_email.trim()}>`;
1964
+ } else {
1965
+ p.author = body.info.author.trim();
1966
+ }
1967
+ } else if (
1968
+ body.info.author_email &&
1969
+ body.info.author_email.trim() !== ""
1970
+ ) {
1971
+ p.author = body.info.author_email.trim();
1972
+ }
1907
1973
  p.description = body.info.summary;
1908
1974
  p.license = findLicenseId(body.info.license);
1909
1975
  if (body.info.home_page) {
@@ -1914,13 +1980,43 @@ const getPyMetadata = async function (pkgList, fetchDepsInfo) {
1914
1980
  }
1915
1981
  }
1916
1982
  // Use the latest version if none specified
1917
- if (
1918
- !p.version ||
1919
- p.version.includes("*") ||
1920
- p.version.includes("<") ||
1921
- p.version.includes(">")
1922
- ) {
1923
- p.version = body.info.version;
1983
+ if (!p.version || !p.version.trim().length) {
1984
+ let versionSpecifiers = undefined;
1985
+ if (p.properties && p.properties.length) {
1986
+ for (const pprop of p.properties) {
1987
+ if (pprop.name === "cdx:pypi:versionSpecifiers") {
1988
+ versionSpecifiers = pprop.value;
1989
+ break;
1990
+ }
1991
+ }
1992
+ } else if (
1993
+ p.version &&
1994
+ (p.version.includes("*") ||
1995
+ p.version.includes("<") ||
1996
+ p.version.includes(">") ||
1997
+ p.version.includes("!"))
1998
+ ) {
1999
+ versionSpecifiers = p.version;
2000
+ }
2001
+ if (versionSpecifiers) {
2002
+ p.version = guessPypiMatchingVersion(
2003
+ Object.keys(body.releases || {}),
2004
+ versionSpecifiers
2005
+ );
2006
+ }
2007
+ // If we have reached here, it means we have not solved the version
2008
+ // So assume latest
2009
+ if (!p.version) {
2010
+ p.version = body.info.version;
2011
+ }
2012
+ } else if (p.version !== body.info.version) {
2013
+ if (!p.properties) {
2014
+ p.properties = [];
2015
+ }
2016
+ p.properties.push({
2017
+ name: "cdx:pypi:latest_version",
2018
+ value: body.info.version
2019
+ });
1924
2020
  }
1925
2021
  if (body.releases && body.releases[p.version]) {
1926
2022
  const digest = body.releases[p.version][0].digests;
@@ -1932,22 +2028,44 @@ const getPyMetadata = async function (pkgList, fetchDepsInfo) {
1932
2028
  }
1933
2029
  cdepList.push(p);
1934
2030
  } catch (err) {
1935
- cdepList.push(p);
1936
2031
  if (DEBUG_MODE) {
1937
- console.error(p.name, err);
2032
+ console.error(p.name, "is not found on PyPI.");
2033
+ console.log(
2034
+ "If this package is available from PyPI or a registry, its name might be different to the module name. Raise a ticket at https://github.com/CycloneDX/cdxgen/issues so that this could be added to the mapping file pypi-pkg-aliases.json"
2035
+ );
2036
+ console.log(
2037
+ "Alternatively, if this is a package that gets installed directly in your environment and offers a python binding, then track such packages manually."
2038
+ );
1938
2039
  }
2040
+ if (!p.version) {
2041
+ if (DEBUG_MODE) {
2042
+ console.log(
2043
+ `Assuming the version as latest for the package ${p.name}`
2044
+ );
2045
+ }
2046
+ p.version = "latest";
2047
+ }
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
+ cdepList.push(p);
1939
2058
  }
1940
2059
  }
1941
2060
  return cdepList;
1942
2061
  };
1943
- exports.getPyMetadata = getPyMetadata;
1944
2062
 
1945
2063
  /**
1946
2064
  * Method to parse bdist_wheel metadata
1947
2065
  *
1948
2066
  * @param {Object} mData bdist_wheel metadata
1949
2067
  */
1950
- const parseBdistMetadata = function (mData) {
2068
+ export const parseBdistMetadata = function (mData) {
1951
2069
  const pkg = {};
1952
2070
  mData.split("\n").forEach((l) => {
1953
2071
  if (l.indexOf("Name: ") > -1) {
@@ -1966,14 +2084,13 @@ const parseBdistMetadata = function (mData) {
1966
2084
  });
1967
2085
  return [pkg];
1968
2086
  };
1969
- exports.parseBdistMetadata = parseBdistMetadata;
1970
2087
 
1971
2088
  /**
1972
2089
  * Method to parse pipfile.lock data
1973
2090
  *
1974
2091
  * @param {Object} lockData JSON data from Pipfile.lock
1975
2092
  */
1976
- const parsePiplockData = async function (lockData) {
2093
+ export const parsePiplockData = async function (lockData) {
1977
2094
  const pkgList = [];
1978
2095
  Object.keys(lockData)
1979
2096
  .filter((i) => i !== "_meta")
@@ -1989,14 +2106,13 @@ const parsePiplockData = async function (lockData) {
1989
2106
  });
1990
2107
  return await getPyMetadata(pkgList, false);
1991
2108
  };
1992
- exports.parsePiplockData = parsePiplockData;
1993
2109
 
1994
2110
  /**
1995
2111
  * Method to parse poetry.lock data
1996
2112
  *
1997
2113
  * @param {Object} lockData JSON data from poetry.lock
1998
2114
  */
1999
- const parsePoetrylockData = async function (lockData) {
2115
+ export const parsePoetrylockData = async function (lockData) {
2000
2116
  const pkgList = [];
2001
2117
  let pkg = null;
2002
2118
  if (!lockData) {
@@ -2031,19 +2147,21 @@ const parsePoetrylockData = async function (lockData) {
2031
2147
  });
2032
2148
  return await getPyMetadata(pkgList, false);
2033
2149
  };
2034
- exports.parsePoetrylockData = parsePoetrylockData;
2035
2150
 
2036
2151
  /**
2037
2152
  * Method to parse requirements.txt data
2038
2153
  *
2039
2154
  * @param {Object} reqData Requirements.txt data
2040
- * @param {Boolean} fetchIndirectDeps Should we also fetch data about indirect dependencies from pypi
2155
+ * @param {Boolean} fetchDepsInfo Fetch dependencies info from pypi
2041
2156
  */
2042
- async function parseReqFile(reqData, fetchIndirectDeps) {
2157
+ export async function parseReqFile(reqData, fetchDepsInfo) {
2043
2158
  const pkgList = [];
2044
2159
  let compScope = undefined;
2045
2160
  reqData.split("\n").forEach((l) => {
2046
2161
  l = l.trim();
2162
+ if (l.startsWith("Skipping line") || l.startsWith("(add")) {
2163
+ return;
2164
+ }
2047
2165
  if (l.includes("# Basic requirements")) {
2048
2166
  compScope = "required";
2049
2167
  } else if (l.includes("added by pip freeze")) {
@@ -2066,36 +2184,53 @@ async function parseReqFile(reqData, fetchIndirectDeps) {
2066
2184
  versionStr = null;
2067
2185
  }
2068
2186
  if (!tmpA[0].includes("=") && !tmpA[0].trim().includes(" ")) {
2069
- pkgList.push({
2070
- name: tmpA[0].trim().replace(";", ""),
2071
- version: versionStr,
2072
- scope: compScope
2073
- });
2187
+ let name = tmpA[0].trim().replace(";", "");
2188
+ if (!PYTHON_STD_MODULES.includes(name)) {
2189
+ pkgList.push({
2190
+ name,
2191
+ version: versionStr,
2192
+ scope: compScope
2193
+ });
2194
+ }
2074
2195
  }
2075
2196
  } else if (l.includes("<") && l.includes(">")) {
2076
2197
  let tmpA = l.split(">");
2077
2198
  let name = tmpA[0].trim().replace(";", "");
2078
- let version = undefined;
2079
- const tmpB = tmpA[1].split("<");
2080
- if (tmpB && tmpB.length) {
2081
- version = tmpB[tmpB.length - 1];
2199
+ const versionSpecifiers = l.replace(name, "");
2200
+ if (!PYTHON_STD_MODULES.includes(name)) {
2201
+ pkgList.push({
2202
+ name,
2203
+ version: undefined,
2204
+ scope: compScope,
2205
+ properties: [
2206
+ {
2207
+ name: "cdx:pypi:versionSpecifiers",
2208
+ value: versionSpecifiers
2209
+ }
2210
+ ]
2211
+ });
2082
2212
  }
2083
- pkgList.push({
2084
- name,
2085
- version,
2086
- scope: compScope
2087
- });
2088
2213
  } else if (/[>|[|@]/.test(l)) {
2089
2214
  let tmpA = l.split(/(>|\[|@)/);
2090
2215
  if (tmpA.includes("#")) {
2091
2216
  tmpA = tmpA.split("#")[0];
2092
2217
  }
2093
2218
  if (!tmpA[0].trim().includes(" ")) {
2094
- pkgList.push({
2095
- name: tmpA[0].trim().replace(";", ""),
2096
- version: null,
2097
- scope: compScope
2098
- });
2219
+ let name = tmpA[0].trim().replace(";", "");
2220
+ const versionSpecifiers = l.replace(name, "");
2221
+ if (!PYTHON_STD_MODULES.includes(name)) {
2222
+ pkgList.push({
2223
+ name,
2224
+ version: undefined,
2225
+ scope: compScope,
2226
+ properties: [
2227
+ {
2228
+ name: "cdx:pypi:versionSpecifiers",
2229
+ value: versionSpecifiers
2230
+ }
2231
+ ]
2232
+ });
2233
+ }
2099
2234
  }
2100
2235
  } else if (l) {
2101
2236
  if (l.includes("#")) {
@@ -2104,31 +2239,99 @@ async function parseReqFile(reqData, fetchIndirectDeps) {
2104
2239
  l = l.trim();
2105
2240
  let tmpA = l.split(/(<|>)/);
2106
2241
  if (tmpA && tmpA.length === 3) {
2107
- pkgList.push({
2108
- name: tmpA[0].trim().replace(";", ""),
2109
- version: tmpA[2].replace(";", ""),
2110
- scope: compScope
2111
- });
2242
+ let name = tmpA[0].trim().replace(";", "");
2243
+ const versionSpecifiers = l.replace(name, "");
2244
+ if (!PYTHON_STD_MODULES.includes(name)) {
2245
+ pkgList.push({
2246
+ name,
2247
+ version: undefined,
2248
+ scope: compScope,
2249
+ properties: [
2250
+ {
2251
+ name: "cdx:pypi:versionSpecifiers",
2252
+ value: versionSpecifiers
2253
+ }
2254
+ ]
2255
+ });
2256
+ }
2112
2257
  } else if (!l.includes(" ")) {
2113
- pkgList.push({
2114
- name: l.replace(";", ""),
2115
- version: null,
2116
- scope: compScope
2117
- });
2258
+ let name = l.replace(";", "");
2259
+ const versionSpecifiers = l.replace(name, "");
2260
+ if (!PYTHON_STD_MODULES.includes(name)) {
2261
+ pkgList.push({
2262
+ name,
2263
+ version: null,
2264
+ scope: compScope,
2265
+ properties: [
2266
+ {
2267
+ name: "cdx:pypi:versionSpecifiers",
2268
+ value: versionSpecifiers
2269
+ }
2270
+ ]
2271
+ });
2272
+ }
2118
2273
  }
2119
2274
  }
2120
2275
  }
2121
2276
  });
2122
- return await getPyMetadata(pkgList, fetchIndirectDeps);
2277
+ return await getPyMetadata(pkgList, fetchDepsInfo);
2123
2278
  }
2124
- exports.parseReqFile = parseReqFile;
2279
+
2280
+ /**
2281
+ * Method to find python modules by parsing the imports and then checking with PyPI to obtain the latest version
2282
+ *
2283
+ * @param {string} src directory
2284
+ * @param {Array} epkgList Existing package list
2285
+ * @returns List of packages
2286
+ */
2287
+ export const getPyModules = async (src, epkgList) => {
2288
+ const allImports = {};
2289
+ const modList = findAppModules(src, "python");
2290
+ const pyDefaultModules = new Set(PYTHON_STD_MODULES);
2291
+ const filteredModList = modList.filter(
2292
+ (x) =>
2293
+ !pyDefaultModules.has(x.name.toLowerCase()) &&
2294
+ !x.name.startsWith("_") &&
2295
+ !x.name.startsWith(".")
2296
+ );
2297
+ let pkgList = filteredModList.map((p) => {
2298
+ return {
2299
+ name:
2300
+ PYPI_MODULE_PACKAGE_MAPPING[p.name.toLowerCase()] ||
2301
+ p.name.replace(/_/g, "-"),
2302
+ version: p.version && p.version.trim().length ? p.version : undefined,
2303
+ scope: "required",
2304
+ properties: [
2305
+ {
2306
+ name: "cdx:pypi:versionSpecifiers",
2307
+ value: p.versionSpecifiers
2308
+ }
2309
+ ]
2310
+ };
2311
+ });
2312
+ pkgList = pkgList.filter(
2313
+ (obj, index) => pkgList.findIndex((i) => i.name === obj.name) === index
2314
+ );
2315
+ // Populate the imports list
2316
+ if (pkgList && pkgList.length) {
2317
+ pkgList.forEach((p) => {
2318
+ allImports[p.name] = true;
2319
+ });
2320
+ }
2321
+ if (epkgList && epkgList.length) {
2322
+ const pkgMaps = epkgList.map((p) => p.name);
2323
+ pkgList = pkgList.filter((p) => !pkgMaps.includes(p.name));
2324
+ }
2325
+ pkgList = await getPyMetadata(pkgList, true);
2326
+ return { allImports, pkgList };
2327
+ };
2125
2328
 
2126
2329
  /**
2127
2330
  * Method to parse setup.py data
2128
2331
  *
2129
2332
  * @param {Object} setupPyData Contents of setup.py
2130
2333
  */
2131
- const parseSetupPyFile = async function (setupPyData) {
2334
+ export const parseSetupPyFile = async function (setupPyData) {
2132
2335
  let lines = [];
2133
2336
  let requires_found = false;
2134
2337
  let should_break = false;
@@ -2150,13 +2353,12 @@ const parseSetupPyFile = async function (setupPyData) {
2150
2353
  });
2151
2354
  return await parseReqFile(lines.join("\n"), false);
2152
2355
  };
2153
- exports.parseSetupPyFile = parseSetupPyFile;
2154
2356
 
2155
2357
  /**
2156
2358
  * Method to construct a github url for the given repo
2157
2359
  * @param {Object} repoMetadata Repo metadata with group and name
2158
2360
  */
2159
- const toGitHubUrl = function (repoMetadata) {
2361
+ export const toGitHubUrl = function (repoMetadata) {
2160
2362
  if (repoMetadata) {
2161
2363
  const group = repoMetadata.group;
2162
2364
  const name = repoMetadata.name;
@@ -2170,7 +2372,6 @@ const toGitHubUrl = function (repoMetadata) {
2170
2372
  return undefined;
2171
2373
  }
2172
2374
  };
2173
- exports.toGitHubUrl = toGitHubUrl;
2174
2375
 
2175
2376
  /**
2176
2377
  * Method to retrieve repo license by querying github api
@@ -2179,7 +2380,7 @@ exports.toGitHubUrl = toGitHubUrl;
2179
2380
  * @param {Object} repoMetadata Object containing group and package name strings
2180
2381
  * @return {String} SPDX license id
2181
2382
  */
2182
- const getRepoLicense = async function (repoUrl, repoMetadata) {
2383
+ export const getRepoLicense = async function (repoUrl, repoMetadata) {
2183
2384
  if (!repoUrl) {
2184
2385
  repoUrl = toGitHubUrl(repoMetadata);
2185
2386
  }
@@ -2195,7 +2396,7 @@ const getRepoLicense = async function (repoUrl, repoMetadata) {
2195
2396
  headers["Authorization"] = "Bearer " + process.env.GITHUB_TOKEN;
2196
2397
  }
2197
2398
  try {
2198
- const res = await got.get(apiUrl, {
2399
+ const res = await cdxgenAgent.get(apiUrl, {
2199
2400
  responseType: "json",
2200
2401
  headers: headers
2201
2402
  });
@@ -2242,14 +2443,13 @@ const getRepoLicense = async function (repoUrl, repoMetadata) {
2242
2443
  }
2243
2444
  return undefined;
2244
2445
  };
2245
- exports.getRepoLicense = getRepoLicense;
2246
2446
 
2247
2447
  /**
2248
2448
  * Method to get go pkg license from go.dev site.
2249
2449
  *
2250
2450
  * @param {Object} repoMetadata Repo metadata
2251
2451
  */
2252
- const getGoPkgLicense = async function (repoMetadata) {
2452
+ export const getGoPkgLicense = async function (repoMetadata) {
2253
2453
  const group = repoMetadata.group;
2254
2454
  const name = repoMetadata.name;
2255
2455
  let pkgUrlPrefix = "https://pkg.go.dev/";
@@ -2262,9 +2462,9 @@ const getGoPkgLicense = async function (repoMetadata) {
2262
2462
  return metadata_cache[pkgUrlPrefix];
2263
2463
  }
2264
2464
  try {
2265
- const res = await got.get(pkgUrlPrefix);
2465
+ const res = await cdxgenAgent.get(pkgUrlPrefix);
2266
2466
  if (res && res.body) {
2267
- const $ = cheerio.load(res.body);
2467
+ const $ = load(res.body);
2268
2468
  let licenses = $("#LICENSE > h2").text().trim();
2269
2469
  if (licenses === "") {
2270
2470
  licenses = $("section.License > h2").text().trim();
@@ -2289,9 +2489,8 @@ const getGoPkgLicense = async function (repoMetadata) {
2289
2489
  }
2290
2490
  return undefined;
2291
2491
  };
2292
- exports.getGoPkgLicense = getGoPkgLicense;
2293
2492
 
2294
- const getGoPkgComponent = async function (group, name, version, hash) {
2493
+ export const getGoPkgComponent = async function (group, name, version, hash) {
2295
2494
  let pkg = {};
2296
2495
  let license = undefined;
2297
2496
  if (fetchLicenses) {
@@ -2314,9 +2513,8 @@ const getGoPkgComponent = async function (group, name, version, hash) {
2314
2513
  };
2315
2514
  return pkg;
2316
2515
  };
2317
- exports.getGoPkgComponent = getGoPkgComponent;
2318
2516
 
2319
- const parseGoModData = async function (goModData, gosumMap) {
2517
+ export const parseGoModData = async function (goModData, gosumMap) {
2320
2518
  const pkgComponentsList = [];
2321
2519
  let isModReplacement = false;
2322
2520
 
@@ -2380,7 +2578,6 @@ const parseGoModData = async function (goModData, gosumMap) {
2380
2578
  metadata_cache = {};
2381
2579
  return pkgComponentsList;
2382
2580
  };
2383
- exports.parseGoModData = parseGoModData;
2384
2581
 
2385
2582
  /**
2386
2583
  * Parse go list output
@@ -2388,7 +2585,7 @@ exports.parseGoModData = parseGoModData;
2388
2585
  * @param {string} rawOutput Output from go list invocation
2389
2586
  * @returns List of packages
2390
2587
  */
2391
- const parseGoListDep = async function (rawOutput, gosumMap) {
2588
+ export const parseGoListDep = async function (rawOutput, gosumMap) {
2392
2589
  if (typeof rawOutput === "string") {
2393
2590
  const deps = [];
2394
2591
  const keys_cache = {};
@@ -2432,14 +2629,13 @@ const parseGoListDep = async function (rawOutput, gosumMap) {
2432
2629
  }
2433
2630
  return [];
2434
2631
  };
2435
- exports.parseGoListDep = parseGoListDep;
2436
2632
 
2437
2633
  /**
2438
2634
  * Parse go mod why output
2439
2635
  * @param {string} rawOutput Output from go mod why
2440
2636
  * @returns package name or none
2441
2637
  */
2442
- const parseGoModWhy = function (rawOutput) {
2638
+ export const parseGoModWhy = function (rawOutput) {
2443
2639
  if (typeof rawOutput === "string") {
2444
2640
  let pkg_name = undefined;
2445
2641
  const tmpA = rawOutput.split("\n");
@@ -2452,9 +2648,8 @@ const parseGoModWhy = function (rawOutput) {
2452
2648
  }
2453
2649
  return undefined;
2454
2650
  };
2455
- exports.parseGoModWhy = parseGoModWhy;
2456
2651
 
2457
- const parseGosumData = async function (gosumData) {
2652
+ export const parseGosumData = async function (gosumData) {
2458
2653
  const pkgList = [];
2459
2654
  if (!gosumData) {
2460
2655
  return pkgList;
@@ -2490,9 +2685,8 @@ const parseGosumData = async function (gosumData) {
2490
2685
  }
2491
2686
  return pkgList;
2492
2687
  };
2493
- exports.parseGosumData = parseGosumData;
2494
2688
 
2495
- const parseGopkgData = async function (gopkgData) {
2689
+ export const parseGopkgData = async function (gopkgData) {
2496
2690
  const pkgList = [];
2497
2691
  if (!gopkgData) {
2498
2692
  return pkgList;
@@ -2540,9 +2734,8 @@ const parseGopkgData = async function (gopkgData) {
2540
2734
  }
2541
2735
  return pkgList;
2542
2736
  };
2543
- exports.parseGopkgData = parseGopkgData;
2544
2737
 
2545
- const parseGoVersionData = async function (buildInfoData) {
2738
+ export const parseGoVersionData = async function (buildInfoData) {
2546
2739
  const pkgList = [];
2547
2740
  if (!buildInfoData) {
2548
2741
  return pkgList;
@@ -2567,14 +2760,13 @@ const parseGoVersionData = async function (buildInfoData) {
2567
2760
  }
2568
2761
  return pkgList;
2569
2762
  };
2570
- exports.parseGoVersionData = parseGoVersionData;
2571
2763
 
2572
2764
  /**
2573
2765
  * Method to query rubygems api for gems details
2574
2766
  *
2575
2767
  * @param {*} pkgList List of packages with metadata
2576
2768
  */
2577
- const getRubyGemsMetadata = async function (pkgList) {
2769
+ export const getRubyGemsMetadata = async function (pkgList) {
2578
2770
  const RUBYGEMS_URL = "https://rubygems.org/api/v1/versions/";
2579
2771
  const rdepList = [];
2580
2772
  for (const p of pkgList) {
@@ -2582,7 +2774,7 @@ const getRubyGemsMetadata = async function (pkgList) {
2582
2774
  if (DEBUG_MODE) {
2583
2775
  console.log(`Querying rubygems.org for ${p.name}`);
2584
2776
  }
2585
- const res = await got.get(RUBYGEMS_URL + p.name + ".json", {
2777
+ const res = await cdxgenAgent.get(RUBYGEMS_URL + p.name + ".json", {
2586
2778
  responseType: "json"
2587
2779
  });
2588
2780
  let body = res.body;
@@ -2618,14 +2810,13 @@ const getRubyGemsMetadata = async function (pkgList) {
2618
2810
  }
2619
2811
  return rdepList;
2620
2812
  };
2621
- exports.getRubyGemsMetadata = getRubyGemsMetadata;
2622
2813
 
2623
2814
  /**
2624
2815
  * Method to parse Gemspec
2625
2816
  *
2626
2817
  * @param {*} gemspecData Gemspec data
2627
2818
  */
2628
- const parseGemspecData = async function (gemspecData) {
2819
+ export const parseGemspecData = async function (gemspecData) {
2629
2820
  let pkgList = [];
2630
2821
  const pkg = {};
2631
2822
  if (!gemspecData) {
@@ -2657,14 +2848,13 @@ const parseGemspecData = async function (gemspecData) {
2657
2848
  return pkgList;
2658
2849
  }
2659
2850
  };
2660
- exports.parseGemspecData = parseGemspecData;
2661
2851
 
2662
2852
  /**
2663
2853
  * Method to parse Gemfile.lock
2664
2854
  *
2665
2855
  * @param {*} gemLockData Gemfile.lock data
2666
2856
  */
2667
- const parseGemfileLockData = async function (gemLockData) {
2857
+ export const parseGemfileLockData = async function (gemLockData) {
2668
2858
  const pkgList = [];
2669
2859
  const pkgnames = {};
2670
2860
  if (!gemLockData) {
@@ -2706,14 +2896,13 @@ const parseGemfileLockData = async function (gemLockData) {
2706
2896
  return pkgList;
2707
2897
  }
2708
2898
  };
2709
- exports.parseGemfileLockData = parseGemfileLockData;
2710
2899
 
2711
2900
  /**
2712
2901
  * Method to retrieve metadata for rust packages by querying crates
2713
2902
  *
2714
2903
  * @param {Array} pkgList Package list
2715
2904
  */
2716
- const getCratesMetadata = async function (pkgList) {
2905
+ export const getCratesMetadata = async function (pkgList) {
2717
2906
  const CRATES_URL = "https://crates.io/api/v1/crates/";
2718
2907
  const cdepList = [];
2719
2908
  for (const p of pkgList) {
@@ -2721,7 +2910,9 @@ const getCratesMetadata = async function (pkgList) {
2721
2910
  if (DEBUG_MODE) {
2722
2911
  console.log(`Querying crates.io for ${p.name}`);
2723
2912
  }
2724
- const res = await got.get(CRATES_URL + p.name, { responseType: "json" });
2913
+ const res = await cdxgenAgent.get(CRATES_URL + p.name, {
2914
+ responseType: "json"
2915
+ });
2725
2916
  const body = res.body.crate;
2726
2917
  p.description = body.description;
2727
2918
  if (res.body.versions) {
@@ -2745,14 +2936,13 @@ const getCratesMetadata = async function (pkgList) {
2745
2936
  }
2746
2937
  return cdepList;
2747
2938
  };
2748
- exports.getCratesMetadata = getCratesMetadata;
2749
2939
 
2750
2940
  /**
2751
2941
  * Method to retrieve metadata for dart packages by querying pub.dev
2752
2942
  *
2753
2943
  * @param {Array} pkgList Package list
2754
2944
  */
2755
- const getDartMetadata = async function (pkgList) {
2945
+ export const getDartMetadata = async function (pkgList) {
2756
2946
  const PUB_DEV_URL = "https://pub.dev/api/packages/";
2757
2947
  const cdepList = [];
2758
2948
  for (const p of pkgList) {
@@ -2760,9 +2950,11 @@ const getDartMetadata = async function (pkgList) {
2760
2950
  if (DEBUG_MODE) {
2761
2951
  console.log(`Querying pub.dev for ${p.name}`);
2762
2952
  }
2763
- const res = await got.get(PUB_DEV_URL + p.name, {
2953
+ const res = await cdxgenAgent.get(PUB_DEV_URL + p.name, {
2764
2954
  responseType: "json",
2765
- Accept: "application/vnd.pub.v2+json"
2955
+ headers: {
2956
+ Accept: "application/vnd.pub.v2+json"
2957
+ }
2766
2958
  });
2767
2959
  if (res && res.body) {
2768
2960
  const versions = res.body.versions;
@@ -2788,9 +2980,8 @@ const getDartMetadata = async function (pkgList) {
2788
2980
  }
2789
2981
  return cdepList;
2790
2982
  };
2791
- exports.getDartMetadata = getDartMetadata;
2792
2983
 
2793
- const parseCargoTomlData = async function (cargoData) {
2984
+ export const parseCargoTomlData = async function (cargoData) {
2794
2985
  let pkgList = [];
2795
2986
  if (!cargoData) {
2796
2987
  return pkgList;
@@ -2825,11 +3016,11 @@ const parseCargoTomlData = async function (cargoData) {
2825
3016
  pkg._integrity = "sha384-" + value;
2826
3017
  break;
2827
3018
  case "name":
2828
- pkg.group = path.dirname(value);
3019
+ pkg.group = dirname(value);
2829
3020
  if (pkg.group === ".") {
2830
3021
  pkg.group = "";
2831
3022
  }
2832
- pkg.name = path.basename(value);
3023
+ pkg.name = basename(value);
2833
3024
  break;
2834
3025
  case "version":
2835
3026
  pkg.version = value;
@@ -2873,9 +3064,8 @@ const parseCargoTomlData = async function (cargoData) {
2873
3064
  return pkgList;
2874
3065
  }
2875
3066
  };
2876
- exports.parseCargoTomlData = parseCargoTomlData;
2877
3067
 
2878
- const parseCargoData = async function (cargoData) {
3068
+ export const parseCargoData = async function (cargoData) {
2879
3069
  const pkgList = [];
2880
3070
  if (!cargoData) {
2881
3071
  return pkgList;
@@ -2903,11 +3093,11 @@ const parseCargoData = async function (cargoData) {
2903
3093
  pkg._integrity = "sha384-" + value;
2904
3094
  break;
2905
3095
  case "name":
2906
- pkg.group = path.dirname(value);
3096
+ pkg.group = dirname(value);
2907
3097
  if (pkg.group === ".") {
2908
3098
  pkg.group = "";
2909
3099
  }
2910
- pkg.name = path.basename(value);
3100
+ pkg.name = basename(value);
2911
3101
  break;
2912
3102
  case "version":
2913
3103
  pkg.version = value;
@@ -2921,9 +3111,8 @@ const parseCargoData = async function (cargoData) {
2921
3111
  return pkgList;
2922
3112
  }
2923
3113
  };
2924
- exports.parseCargoData = parseCargoData;
2925
3114
 
2926
- const parseCargoAuditableData = async function (cargoData) {
3115
+ export const parseCargoAuditableData = async function (cargoData) {
2927
3116
  const pkgList = [];
2928
3117
  if (!cargoData) {
2929
3118
  return pkgList;
@@ -2931,8 +3120,8 @@ const parseCargoAuditableData = async function (cargoData) {
2931
3120
  cargoData.split("\n").forEach((l) => {
2932
3121
  const tmpA = l.split("\t");
2933
3122
  if (tmpA && tmpA.length > 2) {
2934
- let group = path.dirname(tmpA[0].trim());
2935
- const name = path.basename(tmpA[0].trim());
3123
+ let group = dirname(tmpA[0].trim());
3124
+ const name = basename(tmpA[0].trim());
2936
3125
  if (group === ".") {
2937
3126
  group = "";
2938
3127
  }
@@ -2950,9 +3139,8 @@ const parseCargoAuditableData = async function (cargoData) {
2950
3139
  return pkgList;
2951
3140
  }
2952
3141
  };
2953
- exports.parseCargoAuditableData = parseCargoAuditableData;
2954
3142
 
2955
- const parsePubLockData = async function (pubLockData) {
3143
+ export const parsePubLockData = async function (pubLockData) {
2956
3144
  const pkgList = [];
2957
3145
  if (!pubLockData) {
2958
3146
  return pkgList;
@@ -2990,13 +3178,12 @@ const parsePubLockData = async function (pubLockData) {
2990
3178
  return pkgList;
2991
3179
  }
2992
3180
  };
2993
- exports.parsePubLockData = parsePubLockData;
2994
3181
 
2995
- const parsePubYamlData = async function (pubYamlData) {
3182
+ export const parsePubYamlData = async function (pubYamlData) {
2996
3183
  const pkgList = [];
2997
3184
  let yamlObj = undefined;
2998
3185
  try {
2999
- yamlObj = yaml.load(pubYamlData);
3186
+ yamlObj = _load(pubYamlData);
3000
3187
  } catch (err) {
3001
3188
  // continue regardless of error
3002
3189
  }
@@ -3011,13 +3198,12 @@ const parsePubYamlData = async function (pubYamlData) {
3011
3198
  });
3012
3199
  return pkgList;
3013
3200
  };
3014
- exports.parsePubYamlData = parsePubYamlData;
3015
3201
 
3016
- const parseHelmYamlData = async function (helmData) {
3202
+ export const parseHelmYamlData = async function (helmData) {
3017
3203
  const pkgList = [];
3018
3204
  let yamlObj = undefined;
3019
3205
  try {
3020
- yamlObj = yaml.load(helmData);
3206
+ yamlObj = _load(helmData);
3021
3207
  } catch (err) {
3022
3208
  // continue regardless of error
3023
3209
  }
@@ -3077,9 +3263,8 @@ const parseHelmYamlData = async function (helmData) {
3077
3263
  }
3078
3264
  return pkgList;
3079
3265
  };
3080
- exports.parseHelmYamlData = parseHelmYamlData;
3081
3266
 
3082
- const recurseImageNameLookup = (keyValueObj, pkgList, imgList) => {
3267
+ export const recurseImageNameLookup = (keyValueObj, pkgList, imgList) => {
3083
3268
  if (typeof keyValueObj === "string" || keyValueObj instanceof String) {
3084
3269
  return imgList;
3085
3270
  }
@@ -3141,9 +3326,8 @@ const recurseImageNameLookup = (keyValueObj, pkgList, imgList) => {
3141
3326
  }
3142
3327
  return imgList;
3143
3328
  };
3144
- exports.recurseImageNameLookup = recurseImageNameLookup;
3145
3329
 
3146
- const parseContainerSpecData = async function (dcData) {
3330
+ export const parseContainerSpecData = async function (dcData) {
3147
3331
  const pkgList = [];
3148
3332
  const imgList = [];
3149
3333
  if (!dcData.includes("image") && !dcData.includes("kind")) {
@@ -3156,7 +3340,7 @@ const parseContainerSpecData = async function (dcData) {
3156
3340
  for (const dcData of dcDataList) {
3157
3341
  let yamlObj = undefined;
3158
3342
  try {
3159
- yamlObj = yaml.load(dcData);
3343
+ yamlObj = _load(dcData);
3160
3344
  } catch (err) {
3161
3345
  // ignore errors
3162
3346
  }
@@ -3209,9 +3393,8 @@ const parseContainerSpecData = async function (dcData) {
3209
3393
  }
3210
3394
  return pkgList;
3211
3395
  };
3212
- exports.parseContainerSpecData = parseContainerSpecData;
3213
3396
 
3214
- const identifyFlow = function (processingObj) {
3397
+ export const identifyFlow = function (processingObj) {
3215
3398
  let flow = "unknown";
3216
3399
  if (processingObj.sinkId) {
3217
3400
  let sinkId = processingObj.sinkId.toLowerCase();
@@ -3237,8 +3420,8 @@ const convertProcessing = function (processing_list) {
3237
3420
  return data_list;
3238
3421
  };
3239
3422
 
3240
- const parsePrivadoFile = function (f) {
3241
- const pData = fs.readFileSync(f, { encoding: "utf-8" });
3423
+ export const parsePrivadoFile = function (f) {
3424
+ const pData = readFileSync(f, { encoding: "utf-8" });
3242
3425
  const servlist = [];
3243
3426
  if (!pData) {
3244
3427
  return servlist;
@@ -3321,16 +3504,15 @@ const parsePrivadoFile = function (f) {
3321
3504
  }
3322
3505
  return servlist;
3323
3506
  };
3324
- exports.parsePrivadoFile = parsePrivadoFile;
3325
3507
 
3326
- const parseOpenapiSpecData = async function (oaData) {
3508
+ export const parseOpenapiSpecData = async function (oaData) {
3327
3509
  const servlist = [];
3328
3510
  if (!oaData) {
3329
3511
  return servlist;
3330
3512
  }
3331
3513
  try {
3332
3514
  if (oaData.startsWith("openapi:")) {
3333
- oaData = yaml.load(oaData);
3515
+ oaData = _load(oaData);
3334
3516
  } else {
3335
3517
  oaData = JSON.parse(oaData);
3336
3518
  }
@@ -3372,9 +3554,8 @@ const parseOpenapiSpecData = async function (oaData) {
3372
3554
  servlist.push(aservice);
3373
3555
  return servlist;
3374
3556
  };
3375
- exports.parseOpenapiSpecData = parseOpenapiSpecData;
3376
3557
 
3377
- const parseCabalData = async function (cabalData) {
3558
+ export const parseCabalData = async function (cabalData) {
3378
3559
  const pkgList = [];
3379
3560
  if (!cabalData) {
3380
3561
  return pkgList;
@@ -3400,9 +3581,8 @@ const parseCabalData = async function (cabalData) {
3400
3581
  });
3401
3582
  return pkgList;
3402
3583
  };
3403
- exports.parseCabalData = parseCabalData;
3404
3584
 
3405
- const parseMixLockData = async function (mixData) {
3585
+ export const parseMixLockData = async function (mixData) {
3406
3586
  const pkgList = [];
3407
3587
  if (!mixData) {
3408
3588
  return pkgList;
@@ -3427,15 +3607,14 @@ const parseMixLockData = async function (mixData) {
3427
3607
  });
3428
3608
  return pkgList;
3429
3609
  };
3430
- exports.parseMixLockData = parseMixLockData;
3431
3610
 
3432
- const parseGitHubWorkflowData = async function (ghwData) {
3611
+ export const parseGitHubWorkflowData = async function (ghwData) {
3433
3612
  const pkgList = [];
3434
3613
  const keys_cache = {};
3435
3614
  if (!ghwData) {
3436
3615
  return pkgList;
3437
3616
  }
3438
- const yamlObj = yaml.load(ghwData);
3617
+ const yamlObj = _load(ghwData);
3439
3618
  if (!yamlObj) {
3440
3619
  return pkgList;
3441
3620
  }
@@ -3470,15 +3649,14 @@ const parseGitHubWorkflowData = async function (ghwData) {
3470
3649
  }
3471
3650
  return pkgList;
3472
3651
  };
3473
- exports.parseGitHubWorkflowData = parseGitHubWorkflowData;
3474
3652
 
3475
- const parseCloudBuildData = async function (cbwData) {
3653
+ export const parseCloudBuildData = async function (cbwData) {
3476
3654
  const pkgList = [];
3477
3655
  const keys_cache = {};
3478
3656
  if (!cbwData) {
3479
3657
  return pkgList;
3480
3658
  }
3481
- const yamlObj = yaml.load(cbwData);
3659
+ const yamlObj = _load(cbwData);
3482
3660
  if (!yamlObj) {
3483
3661
  return pkgList;
3484
3662
  }
@@ -3487,8 +3665,8 @@ const parseCloudBuildData = async function (cbwData) {
3487
3665
  if (step.name) {
3488
3666
  const tmpA = step.name.split(":");
3489
3667
  if (tmpA.length === 2) {
3490
- let group = path.dirname(tmpA[0]);
3491
- let name = path.basename(tmpA[0]);
3668
+ let group = dirname(tmpA[0]);
3669
+ let name = basename(tmpA[0]);
3492
3670
  if (group === ".") {
3493
3671
  group = "";
3494
3672
  }
@@ -3508,9 +3686,8 @@ const parseCloudBuildData = async function (cbwData) {
3508
3686
  }
3509
3687
  return pkgList;
3510
3688
  };
3511
- exports.parseCloudBuildData = parseCloudBuildData;
3512
3689
 
3513
- const parseConanLockData = async function (conanLockData) {
3690
+ export const parseConanLockData = async function (conanLockData) {
3514
3691
  const pkgList = [];
3515
3692
  if (!conanLockData) {
3516
3693
  return pkgList;
@@ -3530,9 +3707,8 @@ const parseConanLockData = async function (conanLockData) {
3530
3707
  }
3531
3708
  return pkgList;
3532
3709
  };
3533
- exports.parseConanLockData = parseConanLockData;
3534
3710
 
3535
- const parseConanData = async function (conanData) {
3711
+ export const parseConanData = async function (conanData) {
3536
3712
  const pkgList = [];
3537
3713
  if (!conanData) {
3538
3714
  return pkgList;
@@ -3550,9 +3726,8 @@ const parseConanData = async function (conanData) {
3550
3726
  });
3551
3727
  return pkgList;
3552
3728
  };
3553
- exports.parseConanData = parseConanData;
3554
3729
 
3555
- const parseLeiningenData = function (leinData) {
3730
+ export const parseLeiningenData = function (leinData) {
3556
3731
  const pkgList = [];
3557
3732
  if (!leinData) {
3558
3733
  return pkgList;
@@ -3561,7 +3736,7 @@ const parseLeiningenData = function (leinData) {
3561
3736
  if (tmpArr.length > 1) {
3562
3737
  leinData = "(defproject" + tmpArr[1];
3563
3738
  }
3564
- const ednData = ednDataLib.parseEDNString(leinData);
3739
+ const ednData = parseEDNString(leinData);
3565
3740
  for (let k of Object.keys(ednData)) {
3566
3741
  if (k === "list") {
3567
3742
  ednData[k].forEach((jk) => {
@@ -3570,11 +3745,11 @@ const parseLeiningenData = function (leinData) {
3570
3745
  if (Array.isArray(pobjl) && pobjl.length > 1) {
3571
3746
  const psym = pobjl[0].sym;
3572
3747
  if (psym) {
3573
- let group = path.dirname(psym) || "";
3748
+ let group = dirname(psym) || "";
3574
3749
  if (group === ".") {
3575
3750
  group = "";
3576
3751
  }
3577
- const name = path.basename(psym);
3752
+ const name = basename(psym);
3578
3753
  pkgList.push({ group, name, version: pobjl[1] });
3579
3754
  }
3580
3755
  }
@@ -3585,14 +3760,13 @@ const parseLeiningenData = function (leinData) {
3585
3760
  }
3586
3761
  return pkgList;
3587
3762
  };
3588
- exports.parseLeiningenData = parseLeiningenData;
3589
3763
 
3590
- const parseEdnData = function (rawEdnData) {
3764
+ export const parseEdnData = function (rawEdnData) {
3591
3765
  const pkgList = [];
3592
3766
  if (!rawEdnData) {
3593
3767
  return pkgList;
3594
3768
  }
3595
- const ednData = ednDataLib.parseEDNString(rawEdnData);
3769
+ const ednData = parseEDNString(rawEdnData);
3596
3770
  const pkgCache = {};
3597
3771
  for (let k of Object.keys(ednData)) {
3598
3772
  if (k === "map") {
@@ -3613,11 +3787,11 @@ const parseEdnData = function (rawEdnData) {
3613
3787
  if (e["map"]) {
3614
3788
  if (e["map"][0].length > 1) {
3615
3789
  const version = e["map"][0][1];
3616
- let group = path.dirname(psym) || "";
3790
+ let group = dirname(psym) || "";
3617
3791
  if (group === ".") {
3618
3792
  group = "";
3619
3793
  }
3620
- const name = path.basename(psym);
3794
+ const name = basename(psym);
3621
3795
  const cacheKey = group + "-" + name + "-" + version;
3622
3796
  if (!pkgCache[cacheKey]) {
3623
3797
  pkgList.push({ group, name, version });
@@ -3638,9 +3812,8 @@ const parseEdnData = function (rawEdnData) {
3638
3812
  }
3639
3813
  return pkgList;
3640
3814
  };
3641
- exports.parseEdnData = parseEdnData;
3642
3815
 
3643
- const parseNupkg = async function (nupkgFile) {
3816
+ export const parseNupkg = async function (nupkgFile) {
3644
3817
  const pkgList = [];
3645
3818
  let pkg = { group: "" };
3646
3819
  let nuspecData = await readZipEntry(nupkgFile, ".nuspec");
@@ -3650,7 +3823,7 @@ const parseNupkg = async function (nupkgFile) {
3650
3823
  }
3651
3824
  let npkg = undefined;
3652
3825
  try {
3653
- npkg = convert.xml2js(nuspecData, {
3826
+ npkg = xml2js(nuspecData, {
3654
3827
  compact: true,
3655
3828
  alwaysArray: false,
3656
3829
  spaces: 4,
@@ -3684,14 +3857,13 @@ const parseNupkg = async function (nupkgFile) {
3684
3857
  return pkgList;
3685
3858
  }
3686
3859
  };
3687
- exports.parseNupkg = parseNupkg;
3688
3860
 
3689
- const parseCsPkgData = async function (pkgData) {
3861
+ export const parseCsPkgData = async function (pkgData) {
3690
3862
  const pkgList = [];
3691
3863
  if (!pkgData) {
3692
3864
  return pkgList;
3693
3865
  }
3694
- let packages = convert.xml2js(pkgData, {
3866
+ let packages = xml2js(pkgData, {
3695
3867
  compact: true,
3696
3868
  alwaysArray: true,
3697
3869
  spaces: 4,
@@ -3716,14 +3888,13 @@ const parseCsPkgData = async function (pkgData) {
3716
3888
  return pkgList;
3717
3889
  }
3718
3890
  };
3719
- exports.parseCsPkgData = parseCsPkgData;
3720
3891
 
3721
- const parseCsProjData = async function (csProjData) {
3892
+ export const parseCsProjData = async function (csProjData) {
3722
3893
  const pkgList = [];
3723
3894
  if (!csProjData) {
3724
3895
  return pkgList;
3725
3896
  }
3726
- const projects = convert.xml2js(csProjData, {
3897
+ const projects = xml2js(csProjData, {
3727
3898
  compact: true,
3728
3899
  alwaysArray: true,
3729
3900
  spaces: 4,
@@ -3771,9 +3942,8 @@ const parseCsProjData = async function (csProjData) {
3771
3942
  return pkgList;
3772
3943
  }
3773
3944
  };
3774
- exports.parseCsProjData = parseCsProjData;
3775
3945
 
3776
- const parseCsProjAssetsData = async function (csProjData) {
3946
+ export const parseCsProjAssetsData = async function (csProjData) {
3777
3947
  const pkgList = [];
3778
3948
  let pkg = null;
3779
3949
  if (!csProjData) {
@@ -3811,9 +3981,8 @@ const parseCsProjAssetsData = async function (csProjData) {
3811
3981
  return pkgList;
3812
3982
  }
3813
3983
  };
3814
- exports.parseCsProjAssetsData = parseCsProjAssetsData;
3815
3984
 
3816
- const parseCsPkgLockData = async function (csLockData) {
3985
+ export const parseCsPkgLockData = async function (csLockData) {
3817
3986
  const pkgList = [];
3818
3987
  let pkg = null;
3819
3988
  if (!csLockData) {
@@ -3840,14 +4009,13 @@ const parseCsPkgLockData = async function (csLockData) {
3840
4009
  return pkgList;
3841
4010
  }
3842
4011
  };
3843
- exports.parseCsPkgLockData = parseCsPkgLockData;
3844
4012
 
3845
4013
  /**
3846
4014
  * Method to retrieve metadata for nuget packages
3847
4015
  *
3848
4016
  * @param {Array} pkgList Package list
3849
4017
  */
3850
- const getNugetMetadata = async function (pkgList) {
4018
+ export const getNugetMetadata = async function (pkgList) {
3851
4019
  const NUGET_URL = "https://api.nuget.org/v3/registration3/";
3852
4020
  const cdepList = [];
3853
4021
  for (const p of pkgList) {
@@ -3855,7 +4023,7 @@ const getNugetMetadata = async function (pkgList) {
3855
4023
  if (DEBUG_MODE) {
3856
4024
  console.log(`Querying nuget for ${p.name}`);
3857
4025
  }
3858
- const res = await got.get(
4026
+ const res = await cdxgenAgent.get(
3859
4027
  NUGET_URL +
3860
4028
  p.group.toLowerCase() +
3861
4029
  (p.group !== "" ? "." : "") +
@@ -3902,19 +4070,18 @@ const getNugetMetadata = async function (pkgList) {
3902
4070
  }
3903
4071
  return cdepList;
3904
4072
  };
3905
- exports.getNugetMetadata = getNugetMetadata;
3906
4073
 
3907
4074
  /**
3908
4075
  * Parse composer lock file
3909
4076
  *
3910
4077
  * @param {string} pkgLockFile composer.lock file
3911
4078
  */
3912
- const parseComposerLock = function (pkgLockFile) {
4079
+ export const parseComposerLock = function (pkgLockFile) {
3913
4080
  const pkgList = [];
3914
- if (fs.existsSync(pkgLockFile)) {
4081
+ if (existsSync(pkgLockFile)) {
3915
4082
  let lockData = {};
3916
4083
  try {
3917
- lockData = JSON.parse(fs.readFileSync(pkgLockFile, "utf8"));
4084
+ lockData = JSON.parse(readFileSync(pkgLockFile, "utf8"));
3918
4085
  } catch (e) {
3919
4086
  console.error("Invalid composer.lock file:", pkgLockFile);
3920
4087
  return [];
@@ -3934,11 +4101,11 @@ const parseComposerLock = function (pkgLockFile) {
3934
4101
  if (!pkg || !pkg.name || !pkg.version) {
3935
4102
  continue;
3936
4103
  }
3937
- let group = path.dirname(pkg.name);
4104
+ let group = dirname(pkg.name);
3938
4105
  if (group === ".") {
3939
4106
  group = "";
3940
4107
  }
3941
- let name = path.basename(pkg.name);
4108
+ let name = basename(pkg.name);
3942
4109
  pkgList.push({
3943
4110
  group: group,
3944
4111
  name: name,
@@ -3964,17 +4131,16 @@ const parseComposerLock = function (pkgLockFile) {
3964
4131
  }
3965
4132
  return pkgList;
3966
4133
  };
3967
- exports.parseComposerLock = parseComposerLock;
3968
4134
 
3969
4135
  /**
3970
4136
  * Parse sbt lock file
3971
4137
  *
3972
4138
  * @param {string} pkgLockFile build.sbt.lock file
3973
4139
  */
3974
- const parseSbtLock = function (pkgLockFile) {
4140
+ export const parseSbtLock = function (pkgLockFile) {
3975
4141
  const pkgList = [];
3976
- if (fs.existsSync(pkgLockFile)) {
3977
- const lockData = JSON.parse(fs.readFileSync(pkgLockFile, "utf8"));
4142
+ if (existsSync(pkgLockFile)) {
4143
+ const lockData = JSON.parse(readFileSync(pkgLockFile, "utf8"));
3978
4144
  if (lockData && lockData.dependencies) {
3979
4145
  for (let pkg of lockData.dependencies) {
3980
4146
  const artifacts = pkg.artifacts || undefined;
@@ -4008,7 +4174,6 @@ const parseSbtLock = function (pkgLockFile) {
4008
4174
  }
4009
4175
  return pkgList;
4010
4176
  };
4011
- exports.parseSbtLock = parseSbtLock;
4012
4177
 
4013
4178
  /**
4014
4179
  * Convert OS query results
@@ -4016,7 +4181,11 @@ exports.parseSbtLock = parseSbtLock;
4016
4181
  * @param {Object} queryObj Query Object from the queries.json configuration
4017
4182
  * @param {Array} results Query Results
4018
4183
  */
4019
- const convertOSQueryResults = function (queryCategory, queryObj, results) {
4184
+ export const convertOSQueryResults = function (
4185
+ queryCategory,
4186
+ queryObj,
4187
+ results
4188
+ ) {
4020
4189
  const pkgList = [];
4021
4190
  if (results && results.length) {
4022
4191
  for (const res of results) {
@@ -4068,9 +4237,13 @@ const convertOSQueryResults = function (queryCategory, queryObj, results) {
4068
4237
  }
4069
4238
  return pkgList;
4070
4239
  };
4071
- exports.convertOSQueryResults = convertOSQueryResults;
4072
4240
 
4073
- const _swiftDepPkgList = (pkgList, dependenciesList, depKeys, jsonData) => {
4241
+ export const _swiftDepPkgList = (
4242
+ pkgList,
4243
+ dependenciesList,
4244
+ depKeys,
4245
+ jsonData
4246
+ ) => {
4074
4247
  if (jsonData && jsonData.dependencies) {
4075
4248
  for (let adep of jsonData.dependencies) {
4076
4249
  const urlOrPath = adep.url || adep.path;
@@ -4153,7 +4326,7 @@ const _swiftDepPkgList = (pkgList, dependenciesList, depKeys, jsonData) => {
4153
4326
  * @param {string} rawOutput Swift dependencies json output
4154
4327
  * @param {string} pkgFile Package.swift file
4155
4328
  */
4156
- const parseSwiftJsonTree = (rawOutput, pkgFile) => {
4329
+ export const parseSwiftJsonTree = (rawOutput, pkgFile) => {
4157
4330
  if (!rawOutput) {
4158
4331
  return {};
4159
4332
  }
@@ -4228,17 +4401,16 @@ const parseSwiftJsonTree = (rawOutput, pkgFile) => {
4228
4401
  dependenciesList
4229
4402
  };
4230
4403
  };
4231
- exports.parseSwiftJsonTree = parseSwiftJsonTree;
4232
4404
 
4233
4405
  /**
4234
4406
  * Parse swift package resolved file
4235
4407
  * @param {string} resolvedFile Package.resolved file
4236
4408
  */
4237
- const parseSwiftResolved = (resolvedFile) => {
4409
+ export const parseSwiftResolved = (resolvedFile) => {
4238
4410
  const pkgList = [];
4239
- if (fs.existsSync(resolvedFile)) {
4411
+ if (existsSync(resolvedFile)) {
4240
4412
  try {
4241
- const pkgData = JSON.parse(fs.readFileSync(resolvedFile, "utf8"));
4413
+ const pkgData = JSON.parse(readFileSync(resolvedFile, "utf8"));
4242
4414
  let resolvedList = [];
4243
4415
  if (pkgData.pins) {
4244
4416
  resolvedList = pkgData.pins;
@@ -4269,7 +4441,6 @@ const parseSwiftResolved = (resolvedFile) => {
4269
4441
  }
4270
4442
  return pkgList;
4271
4443
  };
4272
- exports.parseSwiftResolved = parseSwiftResolved;
4273
4444
 
4274
4445
  /**
4275
4446
  * Collect maven dependencies
@@ -4277,8 +4448,8 @@ exports.parseSwiftResolved = parseSwiftResolved;
4277
4448
  * @param {string} mavenCmd Maven command to use
4278
4449
  * @param {string} basePath Path to the maven project
4279
4450
  */
4280
- const collectMvnDependencies = function (mavenCmd, basePath) {
4281
- let tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "mvn-deps-"));
4451
+ export const collectMvnDependencies = function (mavenCmd, basePath) {
4452
+ let tempDir = mkdtempSync(join(tmpdir(), "mvn-deps-"));
4282
4453
  console.log(
4283
4454
  `Executing 'mvn dependency:copy-dependencies -DoutputDirectory=${tempDir} -DexcludeTransitive=true -DincludeScope=runtime' in ${basePath}`
4284
4455
  );
@@ -4314,13 +4485,12 @@ const collectMvnDependencies = function (mavenCmd, basePath) {
4314
4485
  jarNSMapping = collectJarNS(tempDir);
4315
4486
  }
4316
4487
  // Clean up
4317
- if (tempDir && tempDir.startsWith(os.tmpdir()) && fs.rmSync) {
4488
+ if (tempDir && tempDir.startsWith(tmpdir()) && rmSync) {
4318
4489
  console.log(`Cleaning up ${tempDir}`);
4319
- fs.rmSync(tempDir, { recursive: true, force: true });
4490
+ rmSync(tempDir, { recursive: true, force: true });
4320
4491
  }
4321
4492
  return jarNSMapping;
4322
4493
  };
4323
- exports.collectMvnDependencies = collectMvnDependencies;
4324
4494
 
4325
4495
  /**
4326
4496
  * Method to collect class names from all jars in a directory
@@ -4329,7 +4499,7 @@ exports.collectMvnDependencies = collectMvnDependencies;
4329
4499
  *
4330
4500
  * @return object containing jar name and class list
4331
4501
  */
4332
- const collectJarNS = function (jarPath) {
4502
+ export const collectJarNS = function (jarPath) {
4333
4503
  const jarNSMapping = {};
4334
4504
  console.log(
4335
4505
  `About to identify class names for all jars in the path ${jarPath}`
@@ -4338,7 +4508,7 @@ const collectJarNS = function (jarPath) {
4338
4508
  const jarFiles = getAllFiles(jarPath, "**/*.jar");
4339
4509
  if (jarFiles && jarFiles.length) {
4340
4510
  for (let jf of jarFiles) {
4341
- const jarname = path.basename(jf);
4511
+ const jarname = basename(jf);
4342
4512
  if (DEBUG_MODE) {
4343
4513
  console.log(`Executing 'jar tf ${jf}'`);
4344
4514
  }
@@ -4375,13 +4545,12 @@ const collectJarNS = function (jarPath) {
4375
4545
  }
4376
4546
  return jarNSMapping;
4377
4547
  };
4378
- exports.collectJarNS = collectJarNS;
4379
4548
 
4380
- const parsePomXml = function (pomXmlData) {
4549
+ export const parsePomXml = function (pomXmlData) {
4381
4550
  if (!pomXmlData) {
4382
4551
  return undefined;
4383
4552
  }
4384
- const project = convert.xml2js(pomXmlData, {
4553
+ const project = xml2js(pomXmlData, {
4385
4554
  compact: true,
4386
4555
  spaces: 4,
4387
4556
  textKey: "_",
@@ -4408,9 +4577,8 @@ const parsePomXml = function (pomXmlData) {
4408
4577
  }
4409
4578
  return undefined;
4410
4579
  };
4411
- exports.parsePomXml = parsePomXml;
4412
4580
 
4413
- const parseJarManifest = function (jarMetadata) {
4581
+ export const parseJarManifest = function (jarMetadata) {
4414
4582
  const metadata = {};
4415
4583
  if (!jarMetadata) {
4416
4584
  return metadata;
@@ -4425,14 +4593,14 @@ const parseJarManifest = function (jarMetadata) {
4425
4593
  });
4426
4594
  return metadata;
4427
4595
  };
4428
- exports.parseJarManifest = parseJarManifest;
4429
4596
 
4430
4597
  const encodeForPurl = (s) => {
4431
4598
  return s
4432
4599
  ? encodeURIComponent(s).replace(/%3A/g, ":").replace(/%2F/g, "/")
4433
4600
  : s;
4434
4601
  };
4435
- exports.encodeForPurl = encodeForPurl;
4602
+ const _encodeForPurl = encodeForPurl;
4603
+ export { _encodeForPurl as encodeForPurl };
4436
4604
 
4437
4605
  /**
4438
4606
  * Method to extract a war or ear file
@@ -4442,27 +4610,23 @@ exports.encodeForPurl = encodeForPurl;
4442
4610
  *
4443
4611
  * @return pkgList Package list
4444
4612
  */
4445
- const extractJarArchive = function (jarFile, tempDir) {
4613
+ export const extractJarArchive = function (jarFile, tempDir) {
4446
4614
  let pkgList = [];
4447
4615
  let jarFiles = [];
4448
- const fname = path.basename(jarFile);
4616
+ const fname = basename(jarFile);
4449
4617
  let pomname = undefined;
4450
4618
  // If there is a pom file in the same directory, try to use it
4451
4619
  if (jarFile.endsWith(".jar")) {
4452
4620
  pomname = jarFile.replace(".jar", ".pom");
4453
4621
  }
4454
- if (pomname && fs.existsSync(pomname)) {
4455
- tempDir = path.dirname(jarFile);
4456
- } else if (!fs.existsSync(path.join(tempDir, fname))) {
4622
+ if (pomname && existsSync(pomname)) {
4623
+ tempDir = dirname(jarFile);
4624
+ } else if (!existsSync(join(tempDir, fname))) {
4457
4625
  // Only copy if the file doesn't exist
4458
- fs.copyFileSync(
4459
- jarFile,
4460
- path.join(tempDir, fname),
4461
- fs.constants.COPYFILE_FICLONE
4462
- );
4626
+ copyFileSync(jarFile, join(tempDir, fname), constants.COPYFILE_FICLONE);
4463
4627
  }
4464
4628
  if (jarFile.endsWith(".war") || jarFile.endsWith(".hpi")) {
4465
- let jarResult = spawnSync("jar", ["-xf", path.join(tempDir, fname)], {
4629
+ let jarResult = spawnSync("jar", ["-xf", join(tempDir, fname)], {
4466
4630
  encoding: "utf-8",
4467
4631
  cwd: tempDir
4468
4632
  });
@@ -4473,17 +4637,17 @@ const extractJarArchive = function (jarFile, tempDir) {
4473
4637
  );
4474
4638
  return pkgList;
4475
4639
  }
4476
- jarFiles = getAllFiles(path.join(tempDir, "WEB-INF", "lib"), "**/*.jar");
4640
+ jarFiles = getAllFiles(join(tempDir, "WEB-INF", "lib"), "**/*.jar");
4477
4641
  if (jarFile.endsWith(".hpi")) {
4478
4642
  jarFiles.push(jarFile);
4479
4643
  }
4480
4644
  } else {
4481
- jarFiles = [path.join(tempDir, fname)];
4645
+ jarFiles = [join(tempDir, fname)];
4482
4646
  }
4483
4647
  if (jarFiles && jarFiles.length) {
4484
4648
  for (let jf of jarFiles) {
4485
4649
  pomname = jf.replace(".jar", ".pom");
4486
- const jarname = path.basename(jf);
4650
+ const jarname = basename(jf);
4487
4651
  // Ignore test jars
4488
4652
  if (
4489
4653
  jarname.endsWith("-tests.jar") ||
@@ -4491,12 +4655,12 @@ const extractJarArchive = function (jarFile, tempDir) {
4491
4655
  ) {
4492
4656
  continue;
4493
4657
  }
4494
- let manifestDir = path.join(tempDir, "META-INF");
4495
- const manifestFile = path.join(manifestDir, "MANIFEST.MF");
4658
+ let manifestDir = join(tempDir, "META-INF");
4659
+ const manifestFile = join(manifestDir, "MANIFEST.MF");
4496
4660
  let jarResult = {
4497
4661
  status: 1
4498
4662
  };
4499
- if (fs.existsSync(pomname)) {
4663
+ if (existsSync(pomname)) {
4500
4664
  jarResult = { status: 0 };
4501
4665
  } else {
4502
4666
  jarResult = spawnSync("jar", ["-xf", jf], {
@@ -4507,9 +4671,9 @@ const extractJarArchive = function (jarFile, tempDir) {
4507
4671
  if (jarResult.status !== 0) {
4508
4672
  console.error(jarResult.stdout, jarResult.stderr);
4509
4673
  } else {
4510
- if (fs.existsSync(manifestFile)) {
4674
+ if (existsSync(manifestFile)) {
4511
4675
  const jarMetadata = parseJarManifest(
4512
- fs.readFileSync(manifestFile, {
4676
+ readFileSync(manifestFile, {
4513
4677
  encoding: "utf-8"
4514
4678
  })
4515
4679
  );
@@ -4540,9 +4704,9 @@ const extractJarArchive = function (jarFile, tempDir) {
4540
4704
  version = version.split(" ")[0];
4541
4705
  }
4542
4706
  if (!name && group) {
4543
- name = path.basename(group.replace(/\./g, "/"));
4707
+ name = basename(group.replace(/\./g, "/"));
4544
4708
  if (!group.startsWith("javax")) {
4545
- group = path.dirname(group.replace(/\./g, "/"));
4709
+ group = dirname(group.replace(/\./g, "/"));
4546
4710
  group = group.replace(/\//g, ".");
4547
4711
  }
4548
4712
  }
@@ -4602,9 +4766,9 @@ const extractJarArchive = function (jarFile, tempDir) {
4602
4766
  }
4603
4767
  }
4604
4768
  try {
4605
- if (fs.rmSync && fs.existsSync(path.join(tempDir, "META-INF"))) {
4769
+ if (rmSync && existsSync(join(tempDir, "META-INF"))) {
4606
4770
  // Clean up META-INF
4607
- fs.rmSync(path.join(tempDir, "META-INF"), {
4771
+ rmSync(join(tempDir, "META-INF"), {
4608
4772
  recursive: true,
4609
4773
  force: true
4610
4774
  });
@@ -4617,7 +4781,6 @@ const extractJarArchive = function (jarFile, tempDir) {
4617
4781
  } // if
4618
4782
  return pkgList;
4619
4783
  };
4620
- exports.extractJarArchive = extractJarArchive;
4621
4784
 
4622
4785
  /**
4623
4786
  * Determine the version of SBT used in compilation of this project.
@@ -4627,18 +4790,17 @@ exports.extractJarArchive = extractJarArchive;
4627
4790
  *
4628
4791
  * @param {string} projectPath Path to the SBT project
4629
4792
  */
4630
- const determineSbtVersion = function (projectPath) {
4631
- const buildPropFile = path.join(projectPath, "project", "build.properties");
4632
- if (fs.existsSync(buildPropFile)) {
4793
+ export const determineSbtVersion = function (projectPath) {
4794
+ const buildPropFile = join(projectPath, "project", "build.properties");
4795
+ if (existsSync(buildPropFile)) {
4633
4796
  let properties = propertiesReader(buildPropFile);
4634
4797
  let property = properties.get("sbt.version");
4635
- if (property != null && semver.valid(property)) {
4798
+ if (property != null && valid(property)) {
4636
4799
  return property;
4637
4800
  }
4638
4801
  }
4639
4802
  return null;
4640
4803
  };
4641
- exports.determineSbtVersion = determineSbtVersion;
4642
4804
 
4643
4805
  /**
4644
4806
  * Adds a new plugin to the SBT project by amending its plugins list.
@@ -4652,22 +4814,17 @@ exports.determineSbtVersion = determineSbtVersion;
4652
4814
  * @param {string} projectPath Path to the SBT project
4653
4815
  * @param {string} plugin Name of the plugin to add
4654
4816
  */
4655
- const addPlugin = function (projectPath, plugin) {
4817
+ export const addPlugin = function (projectPath, plugin) {
4656
4818
  const pluginsFile = sbtPluginsPath(projectPath);
4657
4819
  var originalPluginsFile = null;
4658
- if (fs.existsSync(pluginsFile)) {
4820
+ if (existsSync(pluginsFile)) {
4659
4821
  originalPluginsFile = pluginsFile + ".cdxgen";
4660
- fs.copyFileSync(
4661
- pluginsFile,
4662
- originalPluginsFile,
4663
- fs.constants.COPYFILE_FICLONE
4664
- );
4822
+ copyFileSync(pluginsFile, originalPluginsFile, constants.COPYFILE_FICLONE);
4665
4823
  }
4666
4824
 
4667
- fs.writeFileSync(pluginsFile, plugin, { flag: "a" });
4825
+ writeFileSync(pluginsFile, plugin, { flag: "a" });
4668
4826
  return originalPluginsFile;
4669
4827
  };
4670
- exports.addPlugin = addPlugin;
4671
4828
 
4672
4829
  /**
4673
4830
  * Cleans up modifications to the project's plugins' file made by the
@@ -4676,38 +4833,36 @@ exports.addPlugin = addPlugin;
4676
4833
  * @param {string} projectPath Path to the SBT project
4677
4834
  * @param {string} originalPluginsFile Location of the original plugins file, if any
4678
4835
  */
4679
- const cleanupPlugin = function (projectPath, originalPluginsFile) {
4836
+ export const cleanupPlugin = function (projectPath, originalPluginsFile) {
4680
4837
  const pluginsFile = sbtPluginsPath(projectPath);
4681
- if (fs.existsSync(pluginsFile)) {
4838
+ if (existsSync(pluginsFile)) {
4682
4839
  if (!originalPluginsFile) {
4683
4840
  // just remove the file, it was never there
4684
- fs.unlinkSync(pluginsFile);
4685
- return !fs.existsSync(pluginsFile);
4841
+ unlinkSync(pluginsFile);
4842
+ return !existsSync(pluginsFile);
4686
4843
  } else {
4687
4844
  // Bring back the original file
4688
- fs.copyFileSync(
4845
+ copyFileSync(
4689
4846
  originalPluginsFile,
4690
4847
  pluginsFile,
4691
- fs.constants.COPYFILE_FICLONE
4848
+ constants.COPYFILE_FICLONE
4692
4849
  );
4693
- fs.unlinkSync(originalPluginsFile);
4850
+ unlinkSync(originalPluginsFile);
4694
4851
  return true;
4695
4852
  }
4696
4853
  } else {
4697
4854
  return false;
4698
4855
  }
4699
4856
  };
4700
- exports.cleanupPlugin = cleanupPlugin;
4701
4857
 
4702
4858
  /**
4703
4859
  * Returns a default location of the plugins file.
4704
4860
  *
4705
4861
  * @param {string} projectPath Path to the SBT project
4706
4862
  */
4707
- const sbtPluginsPath = function (projectPath) {
4708
- return path.join(projectPath, "project", "plugins.sbt");
4863
+ export const sbtPluginsPath = function (projectPath) {
4864
+ return join(projectPath, "project", "plugins.sbt");
4709
4865
  };
4710
- exports.sbtPluginsPath = sbtPluginsPath;
4711
4866
 
4712
4867
  /**
4713
4868
  * Method to read a single file entry from a zip file
@@ -4717,7 +4872,7 @@ exports.sbtPluginsPath = sbtPluginsPath;
4717
4872
  *
4718
4873
  * @returns File contents
4719
4874
  */
4720
- const readZipEntry = async function (zipFile, filePattern) {
4875
+ export const readZipEntry = async function (zipFile, filePattern) {
4721
4876
  let retData = undefined;
4722
4877
  try {
4723
4878
  const zip = new StreamZip.async({ file: zipFile });
@@ -4742,7 +4897,6 @@ const readZipEntry = async function (zipFile, filePattern) {
4742
4897
  }
4743
4898
  return retData;
4744
4899
  };
4745
- exports.readZipEntry = readZipEntry;
4746
4900
 
4747
4901
  /**
4748
4902
  * Method to return the gradle command to use.
@@ -4750,39 +4904,38 @@ exports.readZipEntry = readZipEntry;
4750
4904
  * @param {string} srcPath Path to look for gradlew wrapper
4751
4905
  * @param {string} rootPath Root directory to look for gradlew wrapper
4752
4906
  */
4753
- const getGradleCommand = (srcPath, rootPath) => {
4907
+ export const getGradleCommand = (srcPath, rootPath) => {
4754
4908
  let gradleCmd = "gradle";
4755
4909
 
4756
4910
  let findGradleFile = "gradlew";
4757
- if (os.platform() == "win32") {
4911
+ if (platform() == "win32") {
4758
4912
  findGradleFile = "gradlew.bat";
4759
4913
  }
4760
4914
 
4761
- if (fs.existsSync(path.join(srcPath, findGradleFile))) {
4915
+ if (existsSync(join(srcPath, findGradleFile))) {
4762
4916
  // Use local gradle wrapper if available
4763
4917
  // Enable execute permission
4764
4918
  try {
4765
- fs.chmodSync(path.join(srcPath, findGradleFile), 0o775);
4919
+ chmodSync(join(srcPath, findGradleFile), 0o775);
4766
4920
  } catch (e) {
4767
4921
  // continue regardless of error
4768
4922
  }
4769
- gradleCmd = path.resolve(path.join(srcPath, findGradleFile));
4770
- } else if (rootPath && fs.existsSync(path.join(rootPath, findGradleFile))) {
4923
+ gradleCmd = resolve(join(srcPath, findGradleFile));
4924
+ } else if (rootPath && existsSync(join(rootPath, findGradleFile))) {
4771
4925
  // Check if the root directory has a wrapper script
4772
4926
  try {
4773
- fs.chmodSync(path.join(rootPath, findGradleFile), 0o775);
4927
+ chmodSync(join(rootPath, findGradleFile), 0o775);
4774
4928
  } catch (e) {
4775
4929
  // continue regardless of error
4776
4930
  }
4777
- gradleCmd = path.resolve(path.join(rootPath, findGradleFile));
4931
+ gradleCmd = resolve(join(rootPath, findGradleFile));
4778
4932
  } else if (process.env.GRADLE_CMD) {
4779
4933
  gradleCmd = process.env.GRADLE_CMD;
4780
4934
  } else if (process.env.GRADLE_HOME) {
4781
- gradleCmd = path.join(process.env.GRADLE_HOME, "bin", "gradle");
4935
+ gradleCmd = join(process.env.GRADLE_HOME, "bin", "gradle");
4782
4936
  }
4783
4937
  return gradleCmd;
4784
4938
  };
4785
- exports.getGradleCommand = getGradleCommand;
4786
4939
 
4787
4940
  /**
4788
4941
  * Method to return the maven command to use.
@@ -4790,36 +4943,299 @@ exports.getGradleCommand = getGradleCommand;
4790
4943
  * @param {string} srcPath Path to look for maven wrapper
4791
4944
  * @param {string} rootPath Root directory to look for maven wrapper
4792
4945
  */
4793
- const getMavenCommand = (srcPath, rootPath) => {
4946
+ export const getMavenCommand = (srcPath, rootPath) => {
4794
4947
  let mavenCmd = "mvn";
4795
4948
 
4796
4949
  let findMavenFile = "mvnw";
4797
- if (os.platform() == "win32") {
4950
+ if (platform() == "win32") {
4798
4951
  findMavenFile = "mvnw.bat";
4799
4952
  }
4800
4953
 
4801
- if (fs.existsSync(path.join(srcPath, findMavenFile))) {
4954
+ if (existsSync(join(srcPath, findMavenFile))) {
4802
4955
  // Use local maven wrapper if available
4803
4956
  // Enable execute permission
4804
4957
  try {
4805
- fs.chmodSync(path.join(srcPath, findMavenFile), 0o775);
4958
+ chmodSync(join(srcPath, findMavenFile), 0o775);
4806
4959
  } catch (e) {
4807
4960
  // continue regardless of error
4808
4961
  }
4809
- mavenCmd = path.resolve(path.join(srcPath, findMavenFile));
4810
- } else if (rootPath && fs.existsSync(path.join(rootPath, findMavenFile))) {
4962
+ mavenCmd = resolve(join(srcPath, findMavenFile));
4963
+ } else if (rootPath && existsSync(join(rootPath, findMavenFile))) {
4811
4964
  // Check if the root directory has a wrapper script
4812
4965
  try {
4813
- fs.chmodSync(path.join(rootPath, findMavenFile), 0o775);
4966
+ chmodSync(join(rootPath, findMavenFile), 0o775);
4814
4967
  } catch (e) {
4815
4968
  // continue regardless of error
4816
4969
  }
4817
- mavenCmd = path.resolve(path.join(rootPath, findMavenFile));
4970
+ mavenCmd = resolve(join(rootPath, findMavenFile));
4818
4971
  } else if (process.env.MVN_CMD || process.env.MAVEN_CMD) {
4819
4972
  mavenCmd = process.env.MVN_CMD || process.env.MAVEN_CMD;
4820
4973
  } else if (process.env.MAVEN_HOME) {
4821
- mavenCmd = path.join(process.env.MAVEN_HOME, "bin", "mvn");
4974
+ mavenCmd = join(process.env.MAVEN_HOME, "bin", "mvn");
4822
4975
  }
4823
4976
  return mavenCmd;
4824
4977
  };
4825
- exports.getMavenCommand = getMavenCommand;
4978
+
4979
+ /**
4980
+ * Retrieves the atom command by referring to various environment variables
4981
+ */
4982
+ export const getAtomCommand = () => {
4983
+ if (process.env.ATOM_CMD) {
4984
+ return process.env.ATOM_CMD;
4985
+ }
4986
+ if (process.env.ATOM_HOME) {
4987
+ return join(process.env.ATOM_HOME, "bin", "atom");
4988
+ }
4989
+ const NODE_CMD = process.env.NODE_CMD || "node";
4990
+ const localAtom = join(
4991
+ dirName,
4992
+ "node_modules",
4993
+ "@appthreat",
4994
+ "atom",
4995
+ "index.js"
4996
+ );
4997
+ if (existsSync(localAtom)) {
4998
+ return `${NODE_CMD} ${localAtom}`;
4999
+ }
5000
+ return "atom";
5001
+ };
5002
+
5003
+ export const executeAtom = (src, args) => {
5004
+ let ATOM_BIN = getAtomCommand();
5005
+ if (ATOM_BIN.includes(" ")) {
5006
+ const tmpA = ATOM_BIN.split(" ");
5007
+ if (tmpA && tmpA.length > 1) {
5008
+ ATOM_BIN = tmpA[0];
5009
+ args.unshift(tmpA[1]);
5010
+ }
5011
+ }
5012
+ const freeMemoryGB = Math.floor(freemem() / 1024 / 1024 / 1024);
5013
+ if (DEBUG_MODE) {
5014
+ console.log("Execuing", ATOM_BIN, args.join(" "));
5015
+ }
5016
+ const env = {
5017
+ ...process.env,
5018
+ JAVA_OPTS: `-Xms${freeMemoryGB}G -Xmx${freeMemoryGB}G`
5019
+ };
5020
+ const result = spawnSync(ATOM_BIN, args, {
5021
+ cwd: src,
5022
+ encoding: "utf-8",
5023
+ timeout: TIMEOUT_MS,
5024
+ env
5025
+ });
5026
+ if (DEBUG_MODE) {
5027
+ if (result.stdout) {
5028
+ console.log(result.stdout);
5029
+ }
5030
+ if (result.stderr) {
5031
+ console.log(result.stderr);
5032
+ }
5033
+ }
5034
+ return true;
5035
+ };
5036
+
5037
+ /**
5038
+ * Find the imported modules in the application with atom parsedeps command
5039
+ *
5040
+ * @param {string} src
5041
+ * @param {string} language
5042
+ * @returns List of imported modules
5043
+ */
5044
+ export const findAppModules = function (src, language) {
5045
+ const tempDir = mkdtempSync(join(tmpdir(), "atom-deps-"));
5046
+ const atomFile = join(tempDir, "app.atom");
5047
+ const slicesFile = join(tempDir, "slices.json");
5048
+ let retList = [];
5049
+ const args = [
5050
+ "parsedeps",
5051
+ "-l",
5052
+ language,
5053
+ "-o",
5054
+ resolve(atomFile),
5055
+ "--slice-outfile",
5056
+ resolve(slicesFile),
5057
+ resolve(src)
5058
+ ];
5059
+ executeAtom(src, args);
5060
+ if (existsSync(slicesFile)) {
5061
+ const slicesData = JSON.parse(readFileSync(slicesFile), "utf8");
5062
+ if (slicesData && Object.keys(slicesData) && slicesData.modules) {
5063
+ retList = slicesData.modules;
5064
+ }
5065
+ }
5066
+ // Clean up
5067
+ if (tempDir && tempDir.startsWith(tmpdir()) && rmSync) {
5068
+ rmSync(tempDir, { recursive: true, force: true });
5069
+ }
5070
+ return retList;
5071
+ };
5072
+
5073
+ /**
5074
+ * Execute pip freeze by creating a virtual env in a temp directory
5075
+ *
5076
+ * @param {string} basePath Base path
5077
+ * @param {string} reqOrSetupFile Requirements or setup.py file
5078
+ * @returns List of packages from the virtual env
5079
+ */
5080
+ export const executePipFreezeInVenv = async (basePath, reqOrSetupFile) => {
5081
+ let pkgList = [];
5082
+ let result = undefined;
5083
+ const tempDir = mkdtempSync(join(tmpdir(), "cdxgen-venv-"));
5084
+ const env = {
5085
+ ...process.env
5086
+ };
5087
+ /**
5088
+ * Let's start with an attempt to create a new temporary virtual environment in case we aren't in one
5089
+ *
5090
+ * By checking the environment variable "VIRTUAL_ENV" we decide whether to create an env or not
5091
+ */
5092
+ if (!process.env.VIRTUAL_ENV) {
5093
+ result = spawnSync(PYTHON_CMD, ["-m", "venv", tempDir]);
5094
+ if (result.status !== 0 || result.error) {
5095
+ if (DEBUG_MODE) {
5096
+ console.log(result.stderr);
5097
+ }
5098
+ } else {
5099
+ env.VIRTUAL_ENV = tempDir;
5100
+ env.PATH = `${join(tempDir, "bin")}${_delimiter}${
5101
+ process.env.PATH || ""
5102
+ }`;
5103
+ }
5104
+ }
5105
+ /**
5106
+ * We now have a temporary virtual environment so we can attempt to install the project and perform
5107
+ * pip freeze to collect the packages that got installed.
5108
+ * This step is accurate but not reproducible since the resulting list could differ based on various factors
5109
+ * such as the version of python, pip, os, pypi.org availability (and weather?)
5110
+ */
5111
+ if (tempDir === env.VIRTUAL_ENV) {
5112
+ let pipInstallArgs = [
5113
+ "-m",
5114
+ "pip",
5115
+ "install",
5116
+ "--disable-pip-version-check"
5117
+ ];
5118
+ // Requirements.txt could be called with any name so best to check for not setup.py and not pyproject.toml
5119
+ if (
5120
+ !reqOrSetupFile.endsWith("setup.py") &&
5121
+ !reqOrSetupFile.endsWith("pyproject.toml")
5122
+ ) {
5123
+ pipInstallArgs.push("-r");
5124
+ pipInstallArgs.push(resolve(reqOrSetupFile));
5125
+ } else {
5126
+ pipInstallArgs.push(resolve(basePath));
5127
+ }
5128
+ // Attempt to perform pip install
5129
+ result = spawnSync(PYTHON_CMD, pipInstallArgs, {
5130
+ cwd: basePath,
5131
+ encoding: "utf-8",
5132
+ timeout: TIMEOUT_MS,
5133
+ env
5134
+ });
5135
+ if (result.status !== 0 || result.error) {
5136
+ let versionRelatedError = false;
5137
+ if (
5138
+ result.stderr &&
5139
+ (result.stderr.includes(
5140
+ "Could not find a version that satisfies the requirement"
5141
+ ) ||
5142
+ result.stderr.includes("No matching distribution found for"))
5143
+ ) {
5144
+ versionRelatedError = true;
5145
+ console.log(
5146
+ "The version or the version specifiers used for a dependency is invalid. Resolve the below error to improve SBoM accuracy."
5147
+ );
5148
+ console.log(result.stderr);
5149
+ }
5150
+ if (!versionRelatedError && DEBUG_MODE) {
5151
+ console.log("args used:", pipInstallArgs);
5152
+ console.log(
5153
+ "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."
5154
+ );
5155
+ if (platform() == "win32") {
5156
+ console.log(
5157
+ "- Install the appropriate compilers and build tools on Windows by following this documentation - https://wiki.python.org/moin/WindowsCompilers"
5158
+ );
5159
+ } else {
5160
+ console.log(
5161
+ "- For example, you may have to install gcc, gcc-c++ compiler, make tools and additional development libraries using apt-get or yum package manager."
5162
+ );
5163
+ }
5164
+ console.log(
5165
+ "- Certain projects would only build with specific versions of python and OS. Data science and ML related projects might require a conda/anaconda distribution."
5166
+ );
5167
+ console.log("- Check if any git submodules have to be initialized.");
5168
+ }
5169
+ }
5170
+ /**
5171
+ * 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
5172
+ * 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
5173
+ */
5174
+ let pipFreezeArgs = [
5175
+ "-m",
5176
+ "pip",
5177
+ "freeze",
5178
+ "-l",
5179
+ "--exclude-editable",
5180
+ "--disable-pip-version-check"
5181
+ ];
5182
+ if (
5183
+ !reqOrSetupFile.endsWith("setup.py") &&
5184
+ !reqOrSetupFile.endsWith("pyproject.toml")
5185
+ ) {
5186
+ pipFreezeArgs.push("-r");
5187
+ pipFreezeArgs.push(resolve(reqOrSetupFile));
5188
+ }
5189
+ result = spawnSync(PYTHON_CMD, pipFreezeArgs, {
5190
+ cwd: basePath,
5191
+ encoding: "utf-8",
5192
+ timeout: TIMEOUT_MS,
5193
+ env
5194
+ });
5195
+ if (result.status === 0 && result.stdout) {
5196
+ // We now a list from pip freeze that could be parsed to obtain a list
5197
+ // We need to iterate that this list is not reproducible and could vary based on the environment
5198
+ const reqData = Buffer.from(result.stdout).toString();
5199
+ const dlist = await parseReqFile(reqData, false);
5200
+ if (dlist && dlist.length) {
5201
+ pkgList = pkgList.concat(dlist);
5202
+ }
5203
+ } else if (result.status !== 0 || result.error) {
5204
+ if (DEBUG_MODE) {
5205
+ console.log(result.stderr, "args used:", pipFreezeArgs);
5206
+ }
5207
+ }
5208
+ } else {
5209
+ if (DEBUG_MODE) {
5210
+ console.log(
5211
+ "NOTE: Setup and activate a python virtual environment for this project prior to invoking cdxgen to improve SBoM accuracy."
5212
+ );
5213
+ }
5214
+ }
5215
+ // Clean up
5216
+ if (tempDir && tempDir.startsWith(tmpdir()) && rmSync) {
5217
+ rmSync(tempDir, { recursive: true, force: true });
5218
+ }
5219
+ return pkgList;
5220
+ };
5221
+
5222
+ // taken from a very old package https://github.com/keithamus/parse-packagejson-name/blob/master/index.js
5223
+ export const parsePackageJsonName = (name) => {
5224
+ const nameRegExp = /^(?:@([^/]+)\/)?(([^.]+)(?:\.(.*))?)$/;
5225
+ const returnObject = {
5226
+ scope: null,
5227
+ fullName: "",
5228
+ projectName: "",
5229
+ moduleName: ""
5230
+ };
5231
+ const match = (typeof name === "object" ? name.name || "" : name || "").match(
5232
+ nameRegExp
5233
+ );
5234
+ if (match) {
5235
+ returnObject.scope = match[1] || null;
5236
+ returnObject.fullName = match[2] || match[0];
5237
+ returnObject.projectName = match[3] === match[2] ? null : match[3];
5238
+ returnObject.moduleName = match[4] || match[2] || null;
5239
+ }
5240
+ return returnObject;
5241
+ };