@cyclonedx/cdxgen 9.7.5 → 9.8.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,29 +1,50 @@
1
1
  import { globSync } from "glob";
2
- import { homedir, tmpdir, platform } from "node:os";
2
+ import { homedir, platform, tmpdir } from "node:os";
3
3
  import {
4
- dirname,
5
- sep as _sep,
6
4
  basename,
5
+ delimiter as _delimiter,
6
+ dirname,
7
7
  extname,
8
8
  join,
9
9
  resolve,
10
- delimiter as _delimiter
10
+ sep as _sep
11
11
  } from "node:path";
12
12
  import {
13
+ chmodSync,
14
+ constants,
15
+ copyFileSync,
13
16
  existsSync,
14
- readFileSync,
15
17
  lstatSync,
16
18
  mkdtempSync,
19
+ readFileSync,
17
20
  rmSync,
18
- copyFileSync,
19
- constants,
20
- writeFileSync,
21
21
  unlinkSync,
22
- chmodSync
22
+ writeFileSync
23
23
  } from "node:fs";
24
24
  import got from "got";
25
+ import Arborist from "@npmcli/arborist";
26
+ import path from "path";
25
27
  import { xml2js } from "xml-js";
26
28
  import { fileURLToPath } from "node:url";
29
+ import { load } from "cheerio";
30
+ import { load as _load } from "js-yaml";
31
+ import { spawnSync } from "node:child_process";
32
+ import propertiesReader from "properties-reader";
33
+ import {
34
+ clean,
35
+ coerce,
36
+ compare,
37
+ maxSatisfying,
38
+ satisfies,
39
+ valid,
40
+ parse
41
+ } from "semver";
42
+ import StreamZip from "node-stream-zip";
43
+ import { parseEDNString } from "edn-data";
44
+ import { PackageURL } from "packageurl-js";
45
+ import { getTreeWithPlugin } from "./piptree.js";
46
+ import iconv from "iconv-lite";
47
+
27
48
  let url = import.meta.url;
28
49
  if (!url.startsWith("file://")) {
29
50
  url = new URL(`file://${import.meta.url}`).toString();
@@ -45,16 +66,6 @@ const knownLicenses = JSON.parse(
45
66
  const mesonWrapDB = JSON.parse(
46
67
  readFileSync(join(dirNameStr, "data", "wrapdb-releases.json"))
47
68
  );
48
- import { load } from "cheerio";
49
- import { load as _load } from "js-yaml";
50
- import { spawnSync } from "node:child_process";
51
- import propertiesReader from "properties-reader";
52
- import { satisfies, coerce, maxSatisfying, clean, valid } from "semver";
53
- import StreamZip from "node-stream-zip";
54
- import { parseEDNString } from "edn-data";
55
- import { PackageURL } from "packageurl-js";
56
- import { getTreeWithPlugin } from "./piptree.js";
57
- import iconv from "iconv-lite";
58
69
 
59
70
  const selfPJson = JSON.parse(readFileSync(join(dirNameStr, "package.json")));
60
71
  const _version = selfPJson.version;
@@ -80,7 +91,7 @@ export const DEBUG_MODE =
80
91
  const TIMEOUT_MS = parseInt(process.env.CDXGEN_TIMEOUT_MS) || 20 * 60 * 1000;
81
92
 
82
93
  // Metadata cache
83
- let metadata_cache = {};
94
+ export let metadata_cache = {};
84
95
 
85
96
  // Whether test scope shall be included for java/maven projects; default, if unset shall be 'true'
86
97
  export const includeMavenTestScope =
@@ -88,7 +99,7 @@ export const includeMavenTestScope =
88
99
  ["true", "1"].includes(process.env.CDX_MAVEN_INCLUDE_TEST_SCOPE);
89
100
 
90
101
  // Whether license information should be fetched
91
- const fetchLicenses =
102
+ export const FETCH_LICENSE =
92
103
  process.env.FETCH_LICENSE &&
93
104
  ["true", "1"].includes(process.env.FETCH_LICENSE);
94
105
 
@@ -100,7 +111,7 @@ if (process.env.PYTHON_CMD) {
100
111
  }
101
112
 
102
113
  // Custom user-agent for cdxgen
103
- const cdxgenAgent = got.extend({
114
+ export const cdxgenAgent = got.extend({
104
115
  headers: {
105
116
  "user-agent": `@CycloneDX/cdxgen ${_version}`
106
117
  }
@@ -330,121 +341,6 @@ export const getNpmMetadata = async function (pkgList) {
330
341
  return cdepList;
331
342
  };
332
343
 
333
- const _getDepPkgList = async function (
334
- pkgLockFile,
335
- pkgList,
336
- depKeys,
337
- pkg,
338
- versionCache
339
- ) {
340
- const pkgDependencies = {
341
- ...(pkg.packages || {}),
342
- ...(pkg.dependencies || {})
343
- };
344
- if (pkg.packages) {
345
- for (const k in pkg.packages) {
346
- if (k === "") {
347
- continue;
348
- }
349
- const pl = pkg.packages[k];
350
- versionCache[k] = pl.version;
351
- versionCache[k.replaceAll("node_modules/", "")] = pl.version;
352
- }
353
- }
354
- if (pkg && pkgDependencies) {
355
- const pkgKeys = Object.keys(pkgDependencies);
356
- for (const k of pkgKeys) {
357
- // Skip the root package in lockFileVersion 3 and above
358
- if (k === "") {
359
- continue;
360
- }
361
- const name = k;
362
- let version = pkgDependencies[name].version;
363
- if (!version && versionCache[k]) {
364
- version = versionCache[k];
365
- }
366
- if (!version && pkgDependencies["node_modules/" + name]) {
367
- version = pkgDependencies["node_modules/" + name].version;
368
- }
369
- const purl = new PackageURL(
370
- "npm",
371
- "",
372
- name.replaceAll("node_modules/", ""),
373
- version,
374
- null,
375
- null
376
- );
377
- const purlString = decodeURIComponent(purl.toString());
378
- const scope = pkgDependencies[name].dev === true ? "optional" : undefined;
379
- const apkg = {
380
- name: name.replaceAll("node_modules/", ""),
381
- version,
382
- _integrity: pkgDependencies[name].integrity,
383
- scope,
384
- properties: [
385
- {
386
- name: "SrcFile",
387
- value: pkgLockFile
388
- }
389
- ],
390
- evidence: {
391
- identity: {
392
- field: "purl",
393
- confidence: 1,
394
- methods: [
395
- {
396
- technique: "manifest-analysis",
397
- confidence: 1,
398
- value: pkgLockFile
399
- }
400
- ]
401
- }
402
- }
403
- };
404
- pkgList.push(apkg);
405
- if (pkgDependencies[name].dependencies) {
406
- // Include child dependencies
407
- const dependencies = pkgDependencies[name].dependencies;
408
- const pkgDepKeys = Object.keys(dependencies);
409
- const deplist = [];
410
- for (const j in pkgDepKeys) {
411
- const depName = pkgDepKeys[j];
412
- const depVersion =
413
- versionCache[depName] || dependencies[depName].version;
414
- if (!depVersion) {
415
- continue;
416
- }
417
- const deppurl = new PackageURL(
418
- "npm",
419
- "",
420
- depName.replaceAll("node_modules/", ""),
421
- depVersion,
422
- null,
423
- null
424
- );
425
- const deppurlString = decodeURIComponent(deppurl.toString());
426
- deplist.push(deppurlString);
427
- }
428
- depKeys[purlString] = (depKeys[purlString] || []).concat(deplist);
429
- if (pkg.lockfileVersion && pkg.lockfileVersion >= 3) {
430
- // Do not recurse for lock file v3 and above
431
- } else {
432
- await _getDepPkgList(
433
- pkgLockFile,
434
- pkgList,
435
- depKeys,
436
- pkgDependencies[name],
437
- versionCache
438
- );
439
- }
440
- } else if (!depKeys[purlString]) {
441
- depKeys[purlString] = [];
442
- }
443
- }
444
- }
445
- return pkgList;
446
- };
447
-
448
344
  /**
449
345
  * Parse nodejs package json file
450
346
  *
@@ -495,7 +391,7 @@ export const parsePkgJson = async (pkgJsonFile) => {
495
391
  // continue regardless of error
496
392
  }
497
393
  }
498
- if (fetchLicenses && pkgList && pkgList.length) {
394
+ if (FETCH_LICENSE && pkgList && pkgList.length) {
499
395
  if (DEBUG_MODE) {
500
396
  console.log(
501
397
  `About to fetch license information for ${pkgList.length} packages in parsePkgJson`
@@ -514,115 +410,247 @@ export const parsePkgJson = async (pkgJsonFile) => {
514
410
  */
515
411
  export const parsePkgLock = async (pkgLockFile, options = {}) => {
516
412
  let pkgList = [];
517
- const dependenciesList = [];
518
- const depKeys = {};
519
- let rootPkg = {};
520
- const versionCache = {};
413
+ let dependenciesList = [];
521
414
  if (!options) {
522
415
  options = {};
523
416
  }
524
- if (existsSync(pkgLockFile)) {
525
- const lockData = JSON.parse(readFileSync(pkgLockFile, "utf8"));
526
- rootPkg.name = lockData.name || "";
527
- // lockfile v2 onwards
528
- if (lockData.name && lockData.packages && lockData.packages[""]) {
529
- // Build the initial dependency tree for the root package
530
- rootPkg = {
417
+
418
+ if (!existsSync(pkgLockFile)) {
419
+ return {
420
+ pkgList,
421
+ dependenciesList
422
+ };
423
+ }
424
+
425
+ const parseArboristNode = (
426
+ node,
427
+ rootNode,
428
+ parentRef = null,
429
+ visited = new Set(),
430
+ options = {}
431
+ ) => {
432
+ if (visited.has(node)) {
433
+ return { pkgList: [], dependenciesList: [] };
434
+ }
435
+ visited.add(node);
436
+ let pkgList = [];
437
+ let dependenciesList = [];
438
+
439
+ // Create the package entry
440
+ const srcFilePath = node.path.includes(`${_sep}node_modules`)
441
+ ? node.path.split(`${_sep}node_modules`)[0]
442
+ : node.path;
443
+ const scope = node.dev === true ? "optional" : undefined;
444
+ const integrity = node.integrity ? node.integrity : undefined;
445
+
446
+ let pkg = {};
447
+ let purlString = "";
448
+ if (node == rootNode) {
449
+ purlString = decodeURIComponent(
450
+ new PackageURL(
451
+ "npm",
452
+ options.projectGroup || "",
453
+ options.projectName || node.packageName,
454
+ options.projectVersion || node.version,
455
+ null,
456
+ null
457
+ ).toString()
458
+ );
459
+ pkg = {
460
+ author: node.package.author,
531
461
  group: options.projectGroup || "",
532
- name: options.projectName || lockData.name,
533
- version: options.projectVersion || lockData.version,
462
+ name: options.projectName || node.packageName,
463
+ version: options.projectVersion || node.version,
534
464
  type: "application",
535
- "bom-ref": decodeURIComponent(
465
+ "bom-ref": purlString
466
+ };
467
+ } else {
468
+ purlString = decodeURIComponent(
469
+ new PackageURL(
470
+ "npm",
471
+ "",
472
+ node.packageName,
473
+ node.version,
474
+ null,
475
+ null
476
+ ).toString()
477
+ );
478
+ const pkgLockFile = join(
479
+ srcFilePath.replace("/", _sep),
480
+ "package-lock.json"
481
+ );
482
+ pkg = {
483
+ group: "",
484
+ name: node.packageName,
485
+ version: node.version,
486
+ author: node.package.author,
487
+ scope: scope,
488
+ _integrity: integrity,
489
+ properties: [
490
+ {
491
+ name: "SrcFile",
492
+ value: pkgLockFile
493
+ }
494
+ ],
495
+ evidence: {
496
+ identity: {
497
+ field: "purl",
498
+ confidence: 1,
499
+ methods: [
500
+ {
501
+ technique: "manifest-analysis",
502
+ confidence: 1,
503
+ value: pkgLockFile
504
+ }
505
+ ]
506
+ }
507
+ },
508
+ type: parentRef ? "npm" : "application",
509
+ "bom-ref": purlString
510
+ };
511
+ }
512
+ pkgList.push(pkg);
513
+
514
+ // retrieve workspace node pkglists
515
+ let workspaceDependsOn = [];
516
+ if (node.fsChildren && node.fsChildren.size > 0) {
517
+ for (let workspaceNode of node.fsChildren) {
518
+ const {
519
+ pkgList: childPkgList,
520
+ dependenciesList: childDependenciesList
521
+ } = parseArboristNode(workspaceNode, rootNode, purlString, visited);
522
+ pkgList = pkgList.concat(childPkgList);
523
+ dependenciesList = dependenciesList.concat(childDependenciesList);
524
+
525
+ const depWorkspacePurlString = decodeURIComponent(
536
526
  new PackageURL(
537
527
  "npm",
538
- options.projectGroup || "",
539
- options.projectName || lockData.name,
540
- options.projectVersion || lockData.version,
528
+ "",
529
+ workspaceNode.name,
530
+ workspaceNode.version,
541
531
  null,
542
532
  null
543
533
  ).toString()
544
- )
545
- };
546
- } else if (lockData.lockfileVersion === 1) {
547
- let dirName = dirname(pkgLockFile);
548
- const tmpA = dirName.split(_sep);
549
- dirName = tmpA[tmpA.length - 1];
550
- // v1 lock file
551
- rootPkg = {
552
- group: options.projectGroup || "",
553
- name: options.projectName || lockData.name || dirName,
554
- version: options.projectVersion || lockData.version || "",
555
- type: "npm"
556
- };
534
+ );
535
+
536
+ workspaceDependsOn.push(depWorkspacePurlString);
537
+ }
557
538
  }
558
- if (rootPkg && rootPkg.name) {
559
- const purl = new PackageURL(
560
- "npm",
561
- "",
562
- rootPkg.name,
563
- rootPkg.version,
564
- null,
565
- null
566
- );
567
- const purlString = decodeURIComponent(purl.toString());
568
- rootPkg["bom-ref"] = purlString;
569
- pkgList.push(rootPkg);
570
- // npm ls command seems to include both dependencies and devDependencies
571
- // For tree purposes, including only the dependencies should be enough
572
- let rootPkgDeps = [];
573
- if (
574
- lockData.packages &&
575
- lockData.packages[""] &&
576
- lockData.packages[""].dependencies
577
- ) {
578
- rootPkgDeps =
579
- Object.keys(lockData.packages[""].dependencies || {}) || [];
580
- } else if (lockData.dependencies) {
581
- rootPkgDeps = Object.keys(lockData.dependencies || {}) || [];
539
+
540
+ // this handles the case when a node has ["dependencies"] key in a package-lock.json
541
+ // for a node. We exclude the root node because it's already been handled
542
+ let childrenDependsOn = [];
543
+ if (node != rootNode) {
544
+ for (const child of node.children) {
545
+ let childNode = child[1];
546
+ const {
547
+ pkgList: childPkgList,
548
+ dependenciesList: childDependenciesList
549
+ } = parseArboristNode(childNode, rootNode, purlString, visited);
550
+ pkgList = pkgList.concat(childPkgList);
551
+ dependenciesList = dependenciesList.concat(childDependenciesList);
552
+
553
+ const depChildString = decodeURIComponent(
554
+ new PackageURL(
555
+ "npm",
556
+ "",
557
+ childNode.name,
558
+ childNode.version,
559
+ null,
560
+ null
561
+ ).toString()
562
+ );
563
+ childrenDependsOn.push(depChildString);
582
564
  }
583
- const deplist = [];
584
- for (const rd of rootPkgDeps) {
585
- let resolvedVersion = undefined;
586
- if (lockData.packages) {
587
- resolvedVersion = (lockData.packages[`node_modules/${rd}`] || {})
588
- .version;
589
- } else if (lockData.dependencies) {
590
- resolvedVersion = lockData.dependencies[rd].version;
591
- }
592
- if (resolvedVersion) {
593
- const dpurl = decodeURIComponent(
594
- new PackageURL(
595
- "npm",
596
- "",
597
- rd,
598
- resolvedVersion,
599
- null,
600
- null
601
- ).toString()
602
- );
603
- deplist.push(dpurl);
565
+ }
566
+
567
+ // this handles the case when a node has a ["requires"] key
568
+ const pkgDependsOn = [];
569
+ for (const edge of node.edgesOut.values()) {
570
+ let targetVersion;
571
+ let targetName;
572
+
573
+ // if the edge doesn't have an integrity, it's likely a peer dependency
574
+ // which isn't installed
575
+ let edgeToIntegrity = edge.to ? edge.to.integrity : null;
576
+ // let packageName = node.packageName;
577
+ // let edgeName = edge.name;
578
+ if (!edgeToIntegrity) {
579
+ continue;
580
+ }
581
+
582
+ // the edges don't actually contain a version, so we need to search the root node
583
+ // children to find the correct version. we check the node children first, then
584
+ // we check the root node children
585
+ let foundMatch = false;
586
+ for (const child of node.children) {
587
+ if (child[1].integrity == edgeToIntegrity) {
588
+ targetName = child[0].replace(/node_modules\//g, "");
589
+ targetVersion = child[1].version;
590
+ foundMatch = true;
591
+ break;
604
592
  }
605
593
  }
606
- dependenciesList.push({
607
- ref: purlString,
608
- dependsOn: deplist
609
- });
594
+ if (!foundMatch) {
595
+ for (const child of rootNode.children) {
596
+ if (child[1].integrity == edgeToIntegrity) {
597
+ targetName = child[0].replace(/node_modules\//g, "");
598
+ targetVersion = child[1].version;
599
+ break;
600
+ }
601
+ }
602
+ }
603
+
604
+ // if we can't find the version of the edge, continue
605
+ // it may be an optional peer dependency
606
+ if (!targetVersion || !targetName) {
607
+ continue;
608
+ }
609
+
610
+ const depPurlString = decodeURIComponent(
611
+ new PackageURL(
612
+ "npm",
613
+ "",
614
+ targetName,
615
+ targetVersion,
616
+ null,
617
+ null
618
+ ).toString()
619
+ );
620
+
621
+ pkgDependsOn.push(depPurlString);
622
+ if (edge.to == null) continue;
623
+ const { pkgList: childPkgList, dependenciesList: childDependenciesList } =
624
+ parseArboristNode(edge.to, rootNode, purlString, visited);
625
+ pkgList = pkgList.concat(childPkgList);
626
+ dependenciesList = dependenciesList.concat(childDependenciesList);
610
627
  }
611
- pkgList = await _getDepPkgList(
612
- pkgLockFile,
613
- pkgList,
614
- depKeys,
615
- lockData,
616
- versionCache
617
- );
618
- }
619
- for (const dk of Object.keys(depKeys)) {
628
+
620
629
  dependenciesList.push({
621
- ref: dk,
622
- dependsOn: depKeys[dk] || []
630
+ ref: purlString,
631
+ dependsOn: workspaceDependsOn
632
+ .concat(childrenDependsOn)
633
+ .concat(pkgDependsOn)
623
634
  });
624
- }
625
- if (fetchLicenses && pkgList && pkgList.length) {
635
+
636
+ return { pkgList, dependenciesList };
637
+ };
638
+
639
+ const arb = new Arborist({
640
+ path: path.dirname(pkgLockFile),
641
+ // legacyPeerDeps=false enables npm >v3 package dependency resolution
642
+ legacyPeerDeps: false
643
+ });
644
+ const tree = await arb.loadVirtual();
645
+ ({ pkgList, dependenciesList } = parseArboristNode(
646
+ tree,
647
+ tree,
648
+ null,
649
+ new Set(),
650
+ options
651
+ ));
652
+
653
+ if (FETCH_LICENSE && pkgList && pkgList.length) {
626
654
  if (DEBUG_MODE) {
627
655
  console.log(
628
656
  `About to fetch license information for ${pkgList.length} packages in parsePkgLock`
@@ -841,7 +869,7 @@ export const parseYarnLock = async function (yarnLockFile) {
841
869
  }
842
870
  });
843
871
  }
844
- if (fetchLicenses && pkgList && pkgList.length) {
872
+ if (FETCH_LICENSE && pkgList && pkgList.length) {
845
873
  if (DEBUG_MODE) {
846
874
  console.log(
847
875
  `About to fetch license information for ${pkgList.length} packages in parseYarnLock`
@@ -918,7 +946,7 @@ export const parseNodeShrinkwrap = async function (swFile) {
918
946
  }
919
947
  }
920
948
  }
921
- if (fetchLicenses && pkgList && pkgList.length) {
949
+ if (FETCH_LICENSE && pkgList && pkgList.length) {
922
950
  if (DEBUG_MODE) {
923
951
  console.log(
924
952
  `About to fetch license information for ${pkgList.length} packages in parseNodeShrinkwrap`
@@ -1085,7 +1113,7 @@ export const parsePnpmLock = async function (pnpmLock, parentComponent = null) {
1085
1113
  }
1086
1114
  }
1087
1115
  }
1088
- if (fetchLicenses && pkgList && pkgList.length) {
1116
+ if (FETCH_LICENSE && pkgList && pkgList.length) {
1089
1117
  if (DEBUG_MODE) {
1090
1118
  console.log(
1091
1119
  `About to fetch license information for ${pkgList.length} packages in parsePnpmLock`
@@ -1144,7 +1172,7 @@ export const parseBowerJson = async (bowerJsonFile) => {
1144
1172
  // continue regardless of error
1145
1173
  }
1146
1174
  }
1147
- if (fetchLicenses && pkgList && pkgList.length) {
1175
+ if (FETCH_LICENSE && pkgList && pkgList.length) {
1148
1176
  if (DEBUG_MODE) {
1149
1177
  console.log(
1150
1178
  `About to fetch license information for ${pkgList.length} packages in parseBowerJson`
@@ -1230,7 +1258,7 @@ export const parseMinJs = async (minJsFile) => {
1230
1258
  // continue regardless of error
1231
1259
  }
1232
1260
  }
1233
- if (fetchLicenses && pkgList && pkgList.length) {
1261
+ if (FETCH_LICENSE && pkgList && pkgList.length) {
1234
1262
  if (DEBUG_MODE) {
1235
1263
  console.log(
1236
1264
  `About to fetch license information for ${pkgList.length} packages in parseMinJs`
@@ -2068,13 +2096,13 @@ export const getMvnMetadata = async function (pkgList) {
2068
2096
  if (!pkgList || !pkgList.length) {
2069
2097
  return pkgList;
2070
2098
  }
2071
- if (DEBUG_MODE && fetchLicenses) {
2099
+ if (DEBUG_MODE && FETCH_LICENSE) {
2072
2100
  console.log(`About to query maven for ${pkgList.length} packages`);
2073
2101
  }
2074
2102
  for (const p of pkgList) {
2075
2103
  let group = p.group || "";
2076
2104
  // If the package already has key metadata skip querying maven
2077
- if (group && p.name && p.version && !fetchLicenses) {
2105
+ if (group && p.name && p.version && !FETCH_LICENSE) {
2078
2106
  cdepList.push(p);
2079
2107
  continue;
2080
2108
  }
@@ -2208,7 +2236,7 @@ export const guessPypiMatchingVersion = (versionsList, versionSpecifiers) => {
2208
2236
  * @param {Boolean} fetchDepsInfo Fetch dependencies info from pypi
2209
2237
  */
2210
2238
  export const getPyMetadata = async function (pkgList, fetchDepsInfo) {
2211
- if (!fetchLicenses && !fetchDepsInfo) {
2239
+ if (!FETCH_LICENSE && !fetchDepsInfo) {
2212
2240
  return pkgList;
2213
2241
  }
2214
2242
  const PYPI_URL = "https://pypi.org/pypi/";
@@ -2879,7 +2907,7 @@ export const getGoPkgLicense = async function (repoMetadata) {
2879
2907
  export const getGoPkgComponent = async function (group, name, version, hash) {
2880
2908
  let pkg = {};
2881
2909
  let license = undefined;
2882
- if (fetchLicenses) {
2910
+ if (FETCH_LICENSE) {
2883
2911
  if (DEBUG_MODE) {
2884
2912
  console.log(
2885
2913
  `About to fetch go package license information for ${group}:${name}`
@@ -3060,7 +3088,7 @@ export const parseGosumData = async function (gosumData) {
3060
3088
  const version = tmpA[1].replace("/go.mod", "");
3061
3089
  const hash = tmpA[tmpA.length - 1].replace("h1:", "sha256-");
3062
3090
  let license = undefined;
3063
- if (fetchLicenses) {
3091
+ if (FETCH_LICENSE) {
3064
3092
  if (DEBUG_MODE) {
3065
3093
  console.log(
3066
3094
  `About to fetch go package license information for ${name}`
@@ -3112,7 +3140,7 @@ export const parseGopkgData = async function (gopkgData) {
3112
3140
  case "name":
3113
3141
  pkg.group = "";
3114
3142
  pkg.name = value;
3115
- if (fetchLicenses) {
3143
+ if (FETCH_LICENSE) {
3116
3144
  pkg.license = await getGoPkgLicense({
3117
3145
  group: pkg.group,
3118
3146
  name: pkg.name
@@ -3239,7 +3267,7 @@ export const parseGemspecData = async function (gemspecData) {
3239
3267
  }
3240
3268
  });
3241
3269
  pkgList = [pkg];
3242
- if (fetchLicenses) {
3270
+ if (FETCH_LICENSE) {
3243
3271
  return await getRubyGemsMetadata(pkgList);
3244
3272
  } else {
3245
3273
  return pkgList;
@@ -3288,7 +3316,7 @@ export const parseGemfileLockData = async function (gemLockData) {
3288
3316
  specsFound = false;
3289
3317
  }
3290
3318
  });
3291
- if (fetchLicenses) {
3319
+ if (FETCH_LICENSE) {
3292
3320
  return await getRubyGemsMetadata(pkgList);
3293
3321
  } else {
3294
3322
  return pkgList;
@@ -3458,7 +3486,7 @@ export const parseCargoTomlData = async function (cargoData) {
3458
3486
  if (pkg) {
3459
3487
  pkgList.push(pkg);
3460
3488
  }
3461
- if (fetchLicenses) {
3489
+ if (FETCH_LICENSE) {
3462
3490
  return await getCratesMetadata(pkgList);
3463
3491
  } else {
3464
3492
  return pkgList;
@@ -3506,7 +3534,7 @@ export const parseCargoData = async function (cargoData) {
3506
3534
  }
3507
3535
  }
3508
3536
  });
3509
- if (fetchLicenses) {
3537
+ if (FETCH_LICENSE) {
3510
3538
  return await getCratesMetadata(pkgList);
3511
3539
  } else {
3512
3540
  return pkgList;
@@ -3535,7 +3563,7 @@ export const parseCargoAuditableData = async function (cargoData) {
3535
3563
  });
3536
3564
  }
3537
3565
  });
3538
- if (fetchLicenses) {
3566
+ if (FETCH_LICENSE) {
3539
3567
  return await getCratesMetadata(pkgList);
3540
3568
  } else {
3541
3569
  return pkgList;
@@ -3575,7 +3603,7 @@ export const parsePubLockData = async function (pubLockData) {
3575
3603
  }
3576
3604
  }
3577
3605
  });
3578
- if (fetchLicenses) {
3606
+ if (FETCH_LICENSE) {
3579
3607
  return await getDartMetadata(pkgList);
3580
3608
  } else {
3581
3609
  return pkgList;
@@ -4280,11 +4308,7 @@ export const parseNuspecData = async function (nupkgFile, nuspecData) {
4280
4308
  }
4281
4309
  };
4282
4310
  pkgList.push(pkg);
4283
- if (fetchLicenses) {
4284
- return await getNugetMetadata(pkgList);
4285
- } else {
4286
- return pkgList;
4287
- }
4311
+ return pkgList;
4288
4312
  };
4289
4313
 
4290
4314
  export const parseCsPkgData = async function (pkgData) {
@@ -4311,11 +4335,7 @@ export const parseCsPkgData = async function (pkgData) {
4311
4335
  pkg.version = p.version;
4312
4336
  pkgList.push(pkg);
4313
4337
  }
4314
- if (fetchLicenses) {
4315
- return await getNugetMetadata(pkgList);
4316
- } else {
4317
- return pkgList;
4318
- }
4338
+ return pkgList;
4319
4339
  };
4320
4340
 
4321
4341
  export const parseCsProjData = async function (csProjData) {
@@ -4365,11 +4385,7 @@ export const parseCsProjData = async function (csProjData) {
4365
4385
  }
4366
4386
  }
4367
4387
  }
4368
- if (fetchLicenses) {
4369
- return await getNugetMetadata(pkgList);
4370
- } else {
4371
- return pkgList;
4372
- }
4388
+ return pkgList;
4373
4389
  };
4374
4390
 
4375
4391
  export const parseCsProjAssetsData = async function (csProjData) {
@@ -4516,14 +4532,10 @@ export const parseCsProjAssetsData = async function (csProjData) {
4516
4532
  }
4517
4533
  }
4518
4534
  }
4519
- if (fetchLicenses) {
4520
- return await getNugetMetadata(pkgList);
4521
- } else {
4522
- return {
4523
- pkgList,
4524
- dependenciesList
4525
- };
4526
- }
4535
+ return {
4536
+ pkgList,
4537
+ dependenciesList
4538
+ };
4527
4539
  };
4528
4540
 
4529
4541
  export const parseCsPkgLockData = async function (csLockData) {
@@ -4547,120 +4559,7 @@ export const parseCsPkgLockData = async function (csLockData) {
4547
4559
  pkgList.push(pkg);
4548
4560
  }
4549
4561
  }
4550
- if (fetchLicenses) {
4551
- return await getNugetMetadata(pkgList);
4552
- } else {
4553
- return pkgList;
4554
- }
4555
- };
4556
-
4557
- /**
4558
- * Method to retrieve metadata for nuget packages
4559
- *
4560
- * @param {Array} pkgList Package list
4561
- */
4562
- export const getNugetMetadata = async function (pkgList) {
4563
- const NUGET_URL = "https://api.nuget.org/v3/registration3/";
4564
- const cdepList = [];
4565
- for (const p of pkgList) {
4566
- let cacheKey = undefined;
4567
- try {
4568
- if (
4569
- (p.group && p.group.toLowerCase() === "system") ||
4570
- p.name.toLowerCase().startsWith("system")
4571
- ) {
4572
- p.license = "http://go.microsoft.com/fwlink/?LinkId=329770";
4573
- } else if (
4574
- (p.group && p.group.toLowerCase() === "microsoft") ||
4575
- p.name.toLowerCase().startsWith("microsoft")
4576
- ) {
4577
- p.license =
4578
- "http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm";
4579
- } else if (
4580
- (p.group && p.group.toLowerCase() === "nuget") ||
4581
- p.name.toLowerCase().startsWith("nuget")
4582
- ) {
4583
- p.license = "Apache-2.0";
4584
- } else {
4585
- // If there is a version, we can safely use the cache to retrieve the license
4586
- // See: https://github.com/CycloneDX/cdxgen/issues/352
4587
- const twoPartName = p.name.split(".").slice(0, 2).join(".");
4588
- cacheKey = `${p.group}|${twoPartName}`;
4589
- let body = metadata_cache[cacheKey];
4590
- if (body && body.error) {
4591
- cdepList.push(p);
4592
- continue;
4593
- }
4594
- if (!body) {
4595
- if (DEBUG_MODE) {
4596
- console.log(`Querying nuget for ${p.name}`);
4597
- }
4598
- const res = await cdxgenAgent.get(
4599
- NUGET_URL +
4600
- p.group.toLowerCase() +
4601
- (p.group !== "" ? "." : "") +
4602
- p.name.toLowerCase() +
4603
- "/index.json",
4604
- { responseType: "json" }
4605
- );
4606
- const items = res.body.items;
4607
- if (!items || !items[0] || !items[0].items) {
4608
- continue;
4609
- }
4610
- const firstItem = items[0];
4611
- // Work backwards to find the body for the matching version
4612
- body = firstItem.items[firstItem.items.length - 1];
4613
- if (p.version) {
4614
- const newBody = firstItem.items
4615
- .reverse()
4616
- .filter(
4617
- (i) => i.catalogEntry && i.catalogEntry.version === p.version
4618
- );
4619
- if (newBody && newBody.length) {
4620
- body = newBody[0];
4621
- }
4622
- }
4623
- metadata_cache[cacheKey] = body;
4624
- }
4625
- // Set the latest version in case it is missing
4626
- if (!p.version && body.catalogEntry.version) {
4627
- p.version = body.catalogEntry.version;
4628
- }
4629
- p.description = body.catalogEntry.description;
4630
- if (body.catalogEntry.authors) {
4631
- p.author = body.catalogEntry.authors.trim();
4632
- }
4633
- if (
4634
- body.catalogEntry.licenseExpression &&
4635
- body.catalogEntry.licenseExpression !== ""
4636
- ) {
4637
- p.license = findLicenseId(body.catalogEntry.licenseExpression);
4638
- } else if (body.catalogEntry.licenseUrl) {
4639
- p.license = findLicenseId(body.catalogEntry.licenseUrl);
4640
- }
4641
- if (body.catalogEntry.projectUrl) {
4642
- p.repository = { url: body.catalogEntry.projectUrl };
4643
- p.homepage = {
4644
- url:
4645
- "https://www.nuget.org/packages/" +
4646
- p.group +
4647
- (p.group !== "" ? "." : "") +
4648
- p.name +
4649
- "/" +
4650
- p.version +
4651
- "/"
4652
- };
4653
- }
4654
- }
4655
- cdepList.push(p);
4656
- } catch (err) {
4657
- if (cacheKey) {
4658
- metadata_cache[cacheKey] = { error: err.code };
4659
- }
4660
- cdepList.push(p);
4661
- }
4662
- }
4663
- return cdepList;
4562
+ return pkgList;
4664
4563
  };
4665
4564
 
4666
4565
  /**
@@ -7074,13 +6973,10 @@ export const getCppModules = (src, options, osPkgsList, epkgList) => {
7074
6973
  });
7075
6974
  if (options.usagesSlicesFile && existsSync(options.usagesSlicesFile)) {
7076
6975
  sliceData = JSON.parse(readFileSync(options.usagesSlicesFile));
7077
- console.log("Re-using existing slices file", options.usagesSlicesFile);
7078
- } else {
7079
- if (!options.deep) {
7080
- console.log(
7081
- "By default, cdxgen parses c/c++ header files only which might miss system libraries and dependencies used directly in code. Pass the argument --deep to parse both source and header files. Please refer to the instructions in https://github.com/CycloneDX/cdxgen/blob/master/ADVANCED.md"
7082
- );
6976
+ if (DEBUG_MODE) {
6977
+ console.log("Re-using existing slices file", options.usagesSlicesFile);
7083
6978
  }
6979
+ } else {
7084
6980
  sliceData = findAppModules(
7085
6981
  src,
7086
6982
  options.deep ? "c" : "h",
@@ -7096,7 +6992,12 @@ export const getCppModules = (src, options, osPkgsList, epkgList) => {
7096
6992
  }
7097
6993
  let extn = extname(fileName);
7098
6994
  let group = dirname(afile);
7099
- if (group.startsWith(".") || group.startsWith(_sep) || existsSync(afile)) {
6995
+ if (
6996
+ group.startsWith(".") ||
6997
+ group.startsWith(_sep) ||
6998
+ existsSync(resolve(afile)) ||
6999
+ existsSync(resolve(src, afile))
7000
+ ) {
7100
7001
  group = "";
7101
7002
  }
7102
7003
  let version = "";
@@ -7230,3 +7131,206 @@ export const parseCUsageSlice = (sliceData) => {
7230
7131
  }
7231
7132
  return usageData;
7232
7133
  };
7134
+
7135
+ async function getNugetUrl() {
7136
+ const req = "https://api.nuget.org/v3/index.json";
7137
+ const res = await cdxgenAgent.get(req, {
7138
+ responseType: "json"
7139
+ });
7140
+ const urls = res.body.resources;
7141
+ for (const resource of urls) {
7142
+ if (resource["@type"] === "RegistrationsBaseUrl/3.6.0") {
7143
+ return resource["@id"];
7144
+ }
7145
+ }
7146
+ return "https://api.nuget.org/v3/registration3/";
7147
+ }
7148
+
7149
+ async function queryNuget(p, NUGET_URL) {
7150
+ if (DEBUG_MODE) {
7151
+ console.log(`Querying nuget for ${p.name}`);
7152
+ }
7153
+ const np = JSON.parse(JSON.stringify(p));
7154
+ const body = [];
7155
+ const newBody = [];
7156
+ let res = await cdxgenAgent.get(
7157
+ NUGET_URL + np.name.toLowerCase() + "/index.json",
7158
+ { responseType: "json" }
7159
+ );
7160
+ let items = res.body.items;
7161
+ if (!items || !items[0]) {
7162
+ return [np, newBody, body];
7163
+ }
7164
+ if (items[0] && !items[0].items) {
7165
+ if (!p.version || p.version === "0.0.0" || p.version === "latest") {
7166
+ const tmpVersion = parse(res.body.items[res.body.items.length - 1].upper);
7167
+ np.version =
7168
+ tmpVersion.major + "." + tmpVersion.minor + "." + tmpVersion.patch;
7169
+ if (
7170
+ compare(np.version, res.body.items[res.body.items.length - 1].upper) ===
7171
+ 1
7172
+ ) {
7173
+ if (tmpVersion.patch > 0) {
7174
+ np.version =
7175
+ tmpVersion.major +
7176
+ "." +
7177
+ tmpVersion.minor +
7178
+ "." +
7179
+ (tmpVersion.patch - 1).toString();
7180
+ }
7181
+ }
7182
+ }
7183
+ for (const item of items) {
7184
+ // if (!p.version || p.version === "0.0.0" || p.version === "latest") {
7185
+ // const tmpVersion = parse(res.body.items[res.body.items.length - 1].upper);
7186
+ // np.version = tmpVersion.major + "." + tmpVersion.minor + "." + tmpVersion.patch;
7187
+ //
7188
+ // }
7189
+ if (np.version && valid(np.version)) {
7190
+ let lower = compare(item.lower, np.version);
7191
+ let upper = compare(item.upper, np.version);
7192
+ if (lower !== 1 && upper !== -1) {
7193
+ res = await cdxgenAgent.get(item["@id"], { responseType: "json" });
7194
+ newBody.push(
7195
+ res.body.items
7196
+ .reverse()
7197
+ .filter(
7198
+ (i) => i.catalogEntry && i.catalogEntry.version === np.version
7199
+ )
7200
+ );
7201
+ break;
7202
+ }
7203
+ }
7204
+ }
7205
+ } else {
7206
+ if (!p.version || p.version === "0.0.0" || p.version === "latest") {
7207
+ const tmpVersion = parse(res.body.items[res.body.items.length - 1].upper);
7208
+ np.version =
7209
+ tmpVersion.major + "." + tmpVersion.minor + "." + tmpVersion.patch;
7210
+ }
7211
+ const firstItem = items[0];
7212
+ // Work backwards to find the body for the matching version
7213
+ // body.push(firstItem.items[firstItem.items.length - 1])
7214
+ if (np.version) {
7215
+ newBody.push(
7216
+ firstItem.items
7217
+ .reverse()
7218
+ .filter(
7219
+ (i) => i.catalogEntry && i.catalogEntry.version === np.version
7220
+ )
7221
+ );
7222
+ }
7223
+ }
7224
+ return [np, newBody];
7225
+ }
7226
+
7227
+ /**
7228
+ * Method to retrieve metadata for nuget packages
7229
+ *
7230
+ * @param {Array} pkgList Package list
7231
+ */
7232
+ export const getNugetMetadata = async function (
7233
+ pkgList,
7234
+ dependencies = undefined
7235
+ ) {
7236
+ const NUGET_URL = await getNugetUrl();
7237
+ const cdepList = [];
7238
+ const depRepList = {};
7239
+ for (const p of pkgList) {
7240
+ let cacheKey = undefined;
7241
+ try {
7242
+ // If there is a version, we can safely use the cache to retrieve the license
7243
+ // See: https://github.com/CycloneDX/cdxgen/issues/352
7244
+ cacheKey = `${p.name}|${p.version}`;
7245
+ let body = metadata_cache[cacheKey];
7246
+
7247
+ if (body && body.error) {
7248
+ cdepList.push(p);
7249
+ continue;
7250
+ }
7251
+ if (!body) {
7252
+ let newBody = {};
7253
+ let np = {};
7254
+ [np, newBody] = await queryNuget(p, NUGET_URL);
7255
+ if (p.version !== np.version) {
7256
+ const oldRef = p["bom-ref"];
7257
+ p["bom-ref"] = decodeURIComponent(
7258
+ new PackageURL(
7259
+ "nuget",
7260
+ "",
7261
+ np.name,
7262
+ np.version,
7263
+ null,
7264
+ null
7265
+ ).toString()
7266
+ );
7267
+ depRepList[oldRef] = p["bom-ref"];
7268
+ p.version = np.version;
7269
+ }
7270
+ if (newBody && newBody[0].length > 0) {
7271
+ body = newBody[0][0];
7272
+ }
7273
+ if (body) {
7274
+ metadata_cache[cacheKey] = body;
7275
+ // Set the latest version in case it is missing
7276
+ if (!p.version && body.catalogEntry.version) {
7277
+ p.version = body.catalogEntry.version;
7278
+ }
7279
+ p.description = body.catalogEntry.description;
7280
+ if (body.catalogEntry.authors) {
7281
+ p.author = body.catalogEntry.authors.trim();
7282
+ }
7283
+ if (
7284
+ body.catalogEntry.licenseExpression &&
7285
+ body.catalogEntry.licenseExpression !== ""
7286
+ ) {
7287
+ p.license = findLicenseId(body.catalogEntry.licenseExpression);
7288
+ } else if (body.catalogEntry.licenseUrl) {
7289
+ p.license = findLicenseId(body.catalogEntry.licenseUrl);
7290
+ }
7291
+ if (body.catalogEntry.projectUrl) {
7292
+ p.repository = { url: body.catalogEntry.projectUrl };
7293
+ p.homepage = {
7294
+ url:
7295
+ "https://www.nuget.org/packages/" +
7296
+ p.name +
7297
+ "/" +
7298
+ p.version +
7299
+ "/"
7300
+ };
7301
+ }
7302
+ cdepList.push(p);
7303
+ }
7304
+ }
7305
+ } catch (err) {
7306
+ if (cacheKey) {
7307
+ metadata_cache[cacheKey] = { error: err.code };
7308
+ }
7309
+ cdepList.push(p);
7310
+ }
7311
+ }
7312
+ const newDependencies = [].concat(dependencies);
7313
+ if (depRepList && newDependencies.length) {
7314
+ const changed = Object.keys(depRepList);
7315
+ // if (!parentComponent.version || parentComponent.version === "latest" || parentComponent.version === "0.0.0"){
7316
+ // if (changed.includes(parentComponent["bom-ref"])) {
7317
+ // parentComponent["bom-ref"] = depRepList[parentComponent["bom-ref"]["ref"]];
7318
+ // }
7319
+ // }
7320
+ for (const d of newDependencies) {
7321
+ if (changed.length > 0 && changed.includes(d["ref"])) {
7322
+ d["ref"] = depRepList[d["ref"]];
7323
+ }
7324
+ for (const dd in d["dependsOn"]) {
7325
+ if (changed.includes(d["dependsOn"][dd])) {
7326
+ const replace = d["dependsOn"][dd];
7327
+ d["dependsOn"][dd] = depRepList[replace];
7328
+ }
7329
+ }
7330
+ }
7331
+ }
7332
+ return {
7333
+ pkgList: cdepList,
7334
+ dependencies: newDependencies
7335
+ };
7336
+ };