@cyclonedx/cdxgen 10.8.0 → 10.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/display.js +1 -0
- package/docker.js +9 -1
- package/index.js +73 -43
- package/package.json +8 -8
- package/types/display.d.ts.map +1 -1
- package/types/docker.d.ts.map +1 -1
- package/types/index.d.ts +2 -2
- package/types/index.d.ts.map +1 -1
- package/types/utils.d.ts +5 -2
- package/types/utils.d.ts.map +1 -1
- package/utils.js +90 -17
- package/utils.test.js +42 -9
package/README.md
CHANGED
|
@@ -460,6 +460,19 @@ cdxgen can automatically detect names of services from YAML manifests such as do
|
|
|
460
460
|
|
|
461
461
|
Use the [CycloneDX CLI][cyclonedx-cli-github] tool for advanced use cases such as conversion, diff and merging.
|
|
462
462
|
|
|
463
|
+
## Including .NET Global Assembly Cache dependencies in the results
|
|
464
|
+
|
|
465
|
+
Global Assembly Cache (GAC) dependencies must be made available in the build output of the project for cdxgen in order for it to inspect and include in the results. A cdxgen scan with the `--deep` flag will look for additional dependencies in the form of dll files. A simple way to have the dotnet build copy the GAC dependencies into the build directory is to place the file `Directory.Build.props` into the root of the project and ensure the contents include the following:
|
|
466
|
+
```
|
|
467
|
+
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
468
|
+
<ItemDefinitionGroup>
|
|
469
|
+
<Reference>
|
|
470
|
+
<Private>True</Private>
|
|
471
|
+
</Reference>
|
|
472
|
+
</ItemDefinitionGroup>
|
|
473
|
+
</Project>
|
|
474
|
+
```
|
|
475
|
+
|
|
463
476
|
## License
|
|
464
477
|
|
|
465
478
|
Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. See the [LICENSE][github-license] file for the full license.
|
package/display.js
CHANGED
package/docker.js
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
homedir,
|
|
18
18
|
tmpdir,
|
|
19
19
|
} from "node:os";
|
|
20
|
-
import { basename, join } from "node:path";
|
|
20
|
+
import { basename, join, resolve } from "node:path";
|
|
21
21
|
import process from "node:process";
|
|
22
22
|
import stream from "node:stream/promises";
|
|
23
23
|
import { parse } from "node:url";
|
|
@@ -1003,6 +1003,14 @@ export const extractFromManifest = async (
|
|
|
1003
1003
|
* Returns the location of the layers with additional packages related metadata
|
|
1004
1004
|
*/
|
|
1005
1005
|
export const exportImage = async (fullImageName) => {
|
|
1006
|
+
// Safely ignore local directories
|
|
1007
|
+
if (
|
|
1008
|
+
!fullImageName ||
|
|
1009
|
+
fullImageName === "." ||
|
|
1010
|
+
existsSync(resolve(fullImageName))
|
|
1011
|
+
) {
|
|
1012
|
+
return undefined;
|
|
1013
|
+
}
|
|
1006
1014
|
// Try to get the data locally first
|
|
1007
1015
|
const localData = await getImage(fullImageName);
|
|
1008
1016
|
if (!localData) {
|
package/index.js
CHANGED
|
@@ -1641,8 +1641,10 @@ export async function createJavaBom(path, options) {
|
|
|
1641
1641
|
null,
|
|
1642
1642
|
allProjectsStr,
|
|
1643
1643
|
);
|
|
1644
|
-
const splitPropTaskOut =
|
|
1645
|
-
|
|
1644
|
+
const splitPropTaskOut = splitOutputByGradleProjects(
|
|
1645
|
+
parallelPropTaskOut,
|
|
1646
|
+
["properties"],
|
|
1647
|
+
);
|
|
1646
1648
|
|
|
1647
1649
|
for (const [key, propTaskOut] of splitPropTaskOut.entries()) {
|
|
1648
1650
|
let retMap = {};
|
|
@@ -1747,8 +1749,10 @@ export async function createJavaBom(path, options) {
|
|
|
1747
1749
|
const defaultDepTaskArgs = ["--console", "plain", "--build-cache"];
|
|
1748
1750
|
allProjects.push(parentComponent);
|
|
1749
1751
|
let depTaskWithArgs = ["dependencies"];
|
|
1752
|
+
let relevantTasks = ["dependencies"];
|
|
1750
1753
|
if (process.env.GRADLE_DEPENDENCY_TASK) {
|
|
1751
1754
|
depTaskWithArgs = process.env.GRADLE_DEPENDENCY_TASK.split(" ");
|
|
1755
|
+
relevantTasks = process.env.GRADLE_DEPENDENCY_TASK.split(" ");
|
|
1752
1756
|
}
|
|
1753
1757
|
let gradleDepArgs = [];
|
|
1754
1758
|
gradleDepArgs = gradleDepArgs
|
|
@@ -1798,7 +1802,7 @@ export async function createJavaBom(path, options) {
|
|
|
1798
1802
|
const cmdOutput = Buffer.from(sstdout).toString();
|
|
1799
1803
|
const perProjectOutput = splitOutputByGradleProjects(
|
|
1800
1804
|
cmdOutput,
|
|
1801
|
-
|
|
1805
|
+
relevantTasks,
|
|
1802
1806
|
);
|
|
1803
1807
|
for (const [key, singleProjectDepOut] of perProjectOutput.entries()) {
|
|
1804
1808
|
const sp = allProjects
|
|
@@ -2776,7 +2780,7 @@ export async function createPythonBom(path, options) {
|
|
|
2776
2780
|
// Retrieve the tree using virtualenv in deep mode and as a fallback
|
|
2777
2781
|
// This is a slow operation
|
|
2778
2782
|
if (options.deep || !dependencies.length) {
|
|
2779
|
-
retMap = getPipFrozenTree(basePath, f, tempDir);
|
|
2783
|
+
retMap = getPipFrozenTree(basePath, f, tempDir, parentComponent);
|
|
2780
2784
|
if (retMap.pkgList?.length) {
|
|
2781
2785
|
pkgList = pkgList.concat(retMap.pkgList);
|
|
2782
2786
|
}
|
|
@@ -2873,7 +2877,12 @@ export async function createPythonBom(path, options) {
|
|
|
2873
2877
|
if (options.installDeps) {
|
|
2874
2878
|
// If there are multiple requirements files then the tree is getting constructed for each one
|
|
2875
2879
|
// adding to the delay.
|
|
2876
|
-
const pkgMap = getPipFrozenTree(
|
|
2880
|
+
const pkgMap = getPipFrozenTree(
|
|
2881
|
+
basePath,
|
|
2882
|
+
f,
|
|
2883
|
+
tempDir,
|
|
2884
|
+
parentComponent,
|
|
2885
|
+
);
|
|
2877
2886
|
if (pkgMap.pkgList?.length) {
|
|
2878
2887
|
pkgList = pkgList.concat(pkgMap.pkgList);
|
|
2879
2888
|
frozen = pkgMap.frozen;
|
|
@@ -2925,11 +2934,16 @@ export async function createPythonBom(path, options) {
|
|
|
2925
2934
|
if (options.installDeps) {
|
|
2926
2935
|
let pkgMap = undefined;
|
|
2927
2936
|
if (pyProjectMode) {
|
|
2928
|
-
pkgMap = getPipFrozenTree(
|
|
2937
|
+
pkgMap = getPipFrozenTree(
|
|
2938
|
+
path,
|
|
2939
|
+
pyProjectFile,
|
|
2940
|
+
tempDir,
|
|
2941
|
+
parentComponent,
|
|
2942
|
+
);
|
|
2929
2943
|
} else if (setupPyMode) {
|
|
2930
|
-
pkgMap = getPipFrozenTree(path, setupPy, tempDir);
|
|
2944
|
+
pkgMap = getPipFrozenTree(path, setupPy, tempDir, parentComponent);
|
|
2931
2945
|
} else {
|
|
2932
|
-
pkgMap = getPipFrozenTree(path, undefined, tempDir);
|
|
2946
|
+
pkgMap = getPipFrozenTree(path, undefined, tempDir, parentComponent);
|
|
2933
2947
|
}
|
|
2934
2948
|
// Get the imported modules and a dedupe list of packages
|
|
2935
2949
|
const parentDependsOn = new Set();
|
|
@@ -4508,11 +4522,12 @@ export async function createContainerSpecLikeBom(path, options) {
|
|
|
4508
4522
|
}
|
|
4509
4523
|
}
|
|
4510
4524
|
}
|
|
4511
|
-
if (origProjectType
|
|
4525
|
+
if (origProjectType?.includes("universal")) {
|
|
4512
4526
|
// In case of universal, repeat to collect multiX Boms
|
|
4513
|
-
const mbomData = await createMultiXBom(
|
|
4514
|
-
projectType:
|
|
4527
|
+
const mbomData = await createMultiXBom(path, {
|
|
4528
|
+
projectType: [],
|
|
4515
4529
|
multiProject: true,
|
|
4530
|
+
excludeType: options.excludeType,
|
|
4516
4531
|
});
|
|
4517
4532
|
if (mbomData) {
|
|
4518
4533
|
if (mbomData.components?.length) {
|
|
@@ -4536,7 +4551,7 @@ export async function createContainerSpecLikeBom(path, options) {
|
|
|
4536
4551
|
}
|
|
4537
4552
|
if (DEBUG_MODE) {
|
|
4538
4553
|
console.log(
|
|
4539
|
-
`
|
|
4554
|
+
`Received ${components.length} unfiltered components ${dependencies.length} dependencies so far.`,
|
|
4540
4555
|
);
|
|
4541
4556
|
}
|
|
4542
4557
|
}
|
|
@@ -5335,7 +5350,7 @@ export function dedupeBom(options, components, parentComponent, dependencies) {
|
|
|
5335
5350
|
components = trimComponents(components);
|
|
5336
5351
|
if (DEBUG_MODE) {
|
|
5337
5352
|
console.log(
|
|
5338
|
-
`
|
|
5353
|
+
`Obtained ${components.length} components and ${dependencies.length} dependencies after dedupe.`,
|
|
5339
5354
|
);
|
|
5340
5355
|
}
|
|
5341
5356
|
const serialNum = `urn:uuid:${uuidv4()}`;
|
|
@@ -5359,7 +5374,7 @@ export function dedupeBom(options, components, parentComponent, dependencies) {
|
|
|
5359
5374
|
/**
|
|
5360
5375
|
* Function to create bom string for all languages
|
|
5361
5376
|
*
|
|
5362
|
-
* @param {string} pathList list of to the project
|
|
5377
|
+
* @param {string[]} pathList list of to the project
|
|
5363
5378
|
* @param {Object} options Parse options from the cli
|
|
5364
5379
|
*/
|
|
5365
5380
|
export async function createMultiXBom(pathList, options) {
|
|
@@ -5369,6 +5384,10 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5369
5384
|
let parentComponent = determineParentComponent(options) || {};
|
|
5370
5385
|
let parentSubComponents = [];
|
|
5371
5386
|
options.createMultiXBom = true;
|
|
5387
|
+
// Convert single path to an array
|
|
5388
|
+
if (!Array.isArray(pathList)) {
|
|
5389
|
+
pathList = pathList.split(",");
|
|
5390
|
+
}
|
|
5372
5391
|
if (
|
|
5373
5392
|
options.projectType &&
|
|
5374
5393
|
hasAnyProjectType(["oci"], options, false) &&
|
|
@@ -5412,7 +5431,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5412
5431
|
console.log("Scanning", path);
|
|
5413
5432
|
}
|
|
5414
5433
|
// Node.js
|
|
5415
|
-
if (hasAnyProjectType(["js"], options)) {
|
|
5434
|
+
if (hasAnyProjectType(["oci", "js"], options)) {
|
|
5416
5435
|
bomData = await createNodejsBom(path, options);
|
|
5417
5436
|
if (bomData?.bomJson?.components?.length) {
|
|
5418
5437
|
if (DEBUG_MODE) {
|
|
@@ -5437,7 +5456,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5437
5456
|
}
|
|
5438
5457
|
}
|
|
5439
5458
|
// Java
|
|
5440
|
-
if (hasAnyProjectType(["java"], options)) {
|
|
5459
|
+
if (hasAnyProjectType(["oci", "java"], options)) {
|
|
5441
5460
|
bomData = await createJavaBom(path, options);
|
|
5442
5461
|
if (bomData?.bomJson?.components?.length) {
|
|
5443
5462
|
if (DEBUG_MODE) {
|
|
@@ -5461,7 +5480,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5461
5480
|
}
|
|
5462
5481
|
}
|
|
5463
5482
|
}
|
|
5464
|
-
if (hasAnyProjectType(["py"], options)) {
|
|
5483
|
+
if (hasAnyProjectType(["oci", "py"], options)) {
|
|
5465
5484
|
bomData = await createPythonBom(path, options);
|
|
5466
5485
|
if (bomData?.bomJson?.components?.length) {
|
|
5467
5486
|
if (DEBUG_MODE) {
|
|
@@ -5479,7 +5498,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5479
5498
|
}
|
|
5480
5499
|
}
|
|
5481
5500
|
}
|
|
5482
|
-
if (hasAnyProjectType(["go"], options)) {
|
|
5501
|
+
if (hasAnyProjectType(["oci", "go"], options)) {
|
|
5483
5502
|
bomData = await createGoBom(path, options);
|
|
5484
5503
|
if (bomData?.bomJson?.components?.length) {
|
|
5485
5504
|
if (DEBUG_MODE) {
|
|
@@ -5497,7 +5516,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5497
5516
|
}
|
|
5498
5517
|
}
|
|
5499
5518
|
}
|
|
5500
|
-
if (hasAnyProjectType(["rust"], options)) {
|
|
5519
|
+
if (hasAnyProjectType(["oci", "rust"], options)) {
|
|
5501
5520
|
bomData = await createRustBom(path, options);
|
|
5502
5521
|
if (bomData?.bomJson?.components) {
|
|
5503
5522
|
if (DEBUG_MODE) {
|
|
@@ -5521,7 +5540,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5521
5540
|
}
|
|
5522
5541
|
}
|
|
5523
5542
|
}
|
|
5524
|
-
if (hasAnyProjectType(["php"], options)) {
|
|
5543
|
+
if (hasAnyProjectType(["oci", "php"], options)) {
|
|
5525
5544
|
bomData = createPHPBom(path, options);
|
|
5526
5545
|
if (bomData?.bomJson?.components) {
|
|
5527
5546
|
if (DEBUG_MODE) {
|
|
@@ -5539,7 +5558,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5539
5558
|
}
|
|
5540
5559
|
}
|
|
5541
5560
|
}
|
|
5542
|
-
if (hasAnyProjectType(["ruby"], options)) {
|
|
5561
|
+
if (hasAnyProjectType(["oci", "ruby"], options)) {
|
|
5543
5562
|
bomData = await createRubyBom(path, options);
|
|
5544
5563
|
if (bomData?.bomJson?.components) {
|
|
5545
5564
|
if (DEBUG_MODE) {
|
|
@@ -5561,7 +5580,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5561
5580
|
}
|
|
5562
5581
|
}
|
|
5563
5582
|
}
|
|
5564
|
-
if (hasAnyProjectType(["csharp"], options)) {
|
|
5583
|
+
if (hasAnyProjectType(["oci", "csharp"], options)) {
|
|
5565
5584
|
bomData = await createCsharpBom(path, options);
|
|
5566
5585
|
if (bomData?.bomJson?.components?.length) {
|
|
5567
5586
|
if (DEBUG_MODE) {
|
|
@@ -5579,7 +5598,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5579
5598
|
}
|
|
5580
5599
|
}
|
|
5581
5600
|
}
|
|
5582
|
-
if (hasAnyProjectType(["dart"], options)) {
|
|
5601
|
+
if (hasAnyProjectType(["oci", "dart"], options)) {
|
|
5583
5602
|
bomData = await createDartBom(path, options);
|
|
5584
5603
|
if (bomData?.bomJson?.components) {
|
|
5585
5604
|
if (DEBUG_MODE) {
|
|
@@ -5597,7 +5616,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5597
5616
|
}
|
|
5598
5617
|
}
|
|
5599
5618
|
}
|
|
5600
|
-
if (hasAnyProjectType(["haskell"], options)) {
|
|
5619
|
+
if (hasAnyProjectType(["oci", "haskell"], options)) {
|
|
5601
5620
|
bomData = createHaskellBom(path, options);
|
|
5602
5621
|
if (bomData?.bomJson?.components) {
|
|
5603
5622
|
if (DEBUG_MODE) {
|
|
@@ -5615,7 +5634,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5615
5634
|
}
|
|
5616
5635
|
}
|
|
5617
5636
|
}
|
|
5618
|
-
if (hasAnyProjectType(["elixir"], options)) {
|
|
5637
|
+
if (hasAnyProjectType(["oci", "elixir"], options)) {
|
|
5619
5638
|
bomData = createElixirBom(path, options);
|
|
5620
5639
|
if (bomData?.bomJson?.components) {
|
|
5621
5640
|
if (DEBUG_MODE) {
|
|
@@ -5633,7 +5652,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5633
5652
|
}
|
|
5634
5653
|
}
|
|
5635
5654
|
}
|
|
5636
|
-
if (hasAnyProjectType(["c"], options)) {
|
|
5655
|
+
if (hasAnyProjectType(["oci", "c"], options)) {
|
|
5637
5656
|
bomData = createCppBom(path, options);
|
|
5638
5657
|
if (bomData?.bomJson?.components) {
|
|
5639
5658
|
if (DEBUG_MODE) {
|
|
@@ -5651,7 +5670,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5651
5670
|
}
|
|
5652
5671
|
}
|
|
5653
5672
|
}
|
|
5654
|
-
if (hasAnyProjectType(["clojure"], options)) {
|
|
5673
|
+
if (hasAnyProjectType(["oci", "clojure"], options)) {
|
|
5655
5674
|
bomData = createClojureBom(path, options);
|
|
5656
5675
|
if (bomData?.bomJson?.components) {
|
|
5657
5676
|
if (DEBUG_MODE) {
|
|
@@ -5669,7 +5688,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5669
5688
|
}
|
|
5670
5689
|
}
|
|
5671
5690
|
}
|
|
5672
|
-
if (hasAnyProjectType(["github"], options)) {
|
|
5691
|
+
if (hasAnyProjectType(["oci", "github"], options)) {
|
|
5673
5692
|
bomData = createGitHubBom(path, options);
|
|
5674
5693
|
if (bomData?.bomJson?.components) {
|
|
5675
5694
|
if (DEBUG_MODE) {
|
|
@@ -5687,7 +5706,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5687
5706
|
}
|
|
5688
5707
|
}
|
|
5689
5708
|
}
|
|
5690
|
-
if (hasAnyProjectType(["cloudbuild"], options)) {
|
|
5709
|
+
if (hasAnyProjectType(["oci", "cloudbuild"], options)) {
|
|
5691
5710
|
bomData = createCloudBuildBom(path, options);
|
|
5692
5711
|
if (bomData?.bomJson?.components) {
|
|
5693
5712
|
if (DEBUG_MODE) {
|
|
@@ -5705,7 +5724,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5705
5724
|
}
|
|
5706
5725
|
}
|
|
5707
5726
|
}
|
|
5708
|
-
if (hasAnyProjectType(["swift"], options)) {
|
|
5727
|
+
if (hasAnyProjectType(["oci", "swift"], options)) {
|
|
5709
5728
|
bomData = await createSwiftBom(path, options);
|
|
5710
5729
|
if (bomData?.bomJson?.components?.length) {
|
|
5711
5730
|
if (DEBUG_MODE) {
|
|
@@ -5797,6 +5816,14 @@ export async function createMultiXBom(pathList, options) {
|
|
|
5797
5816
|
delete parentComponent.components;
|
|
5798
5817
|
}
|
|
5799
5818
|
}
|
|
5819
|
+
// some cleanup, but not complete
|
|
5820
|
+
for (const path of pathList) {
|
|
5821
|
+
if (path.startsWith(join(tmpdir(), "docker-images-"))) {
|
|
5822
|
+
if (rmSync) {
|
|
5823
|
+
rmSync(path, { recursive: true, force: true });
|
|
5824
|
+
}
|
|
5825
|
+
}
|
|
5826
|
+
}
|
|
5800
5827
|
return dedupeBom(options, components, parentComponent, dependencies);
|
|
5801
5828
|
}
|
|
5802
5829
|
|
|
@@ -5810,8 +5837,7 @@ export async function createXBom(path, options) {
|
|
|
5810
5837
|
try {
|
|
5811
5838
|
accessSync(path, constants.R_OK);
|
|
5812
5839
|
} catch (err) {
|
|
5813
|
-
|
|
5814
|
-
process.exit(1);
|
|
5840
|
+
return undefined;
|
|
5815
5841
|
}
|
|
5816
5842
|
// node.js - package.json
|
|
5817
5843
|
if (
|
|
@@ -6152,7 +6178,9 @@ export async function createBom(path, options) {
|
|
|
6152
6178
|
}
|
|
6153
6179
|
isContainerMode = true;
|
|
6154
6180
|
} else if (
|
|
6155
|
-
(options.projectType &&
|
|
6181
|
+
(options.projectType &&
|
|
6182
|
+
!options.projectType?.includes("universal") &&
|
|
6183
|
+
hasAnyProjectType(["oci"], options, false)) ||
|
|
6156
6184
|
path.startsWith("docker.io") ||
|
|
6157
6185
|
path.startsWith("quay.io") ||
|
|
6158
6186
|
path.startsWith("ghcr.io") ||
|
|
@@ -6161,15 +6189,17 @@ export async function createBom(path, options) {
|
|
|
6161
6189
|
path.includes(":latest")
|
|
6162
6190
|
) {
|
|
6163
6191
|
exportData = await exportImage(path);
|
|
6164
|
-
if (
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
)
|
|
6168
|
-
|
|
6169
|
-
|
|
6192
|
+
if (exportData) {
|
|
6193
|
+
isContainerMode = true;
|
|
6194
|
+
} else {
|
|
6195
|
+
if (DEBUG_MODE) {
|
|
6196
|
+
console.log(path, "doesn't appear to be a valid container image.");
|
|
6197
|
+
}
|
|
6170
6198
|
}
|
|
6171
|
-
|
|
6172
|
-
|
|
6199
|
+
} else if (
|
|
6200
|
+
!options.projectType?.includes("universal") &&
|
|
6201
|
+
hasAnyProjectType(["oci-dir"], options, false)
|
|
6202
|
+
) {
|
|
6173
6203
|
isContainerMode = true;
|
|
6174
6204
|
exportData = {
|
|
6175
6205
|
inspectData: undefined,
|
|
@@ -6254,7 +6284,7 @@ export async function createBom(path, options) {
|
|
|
6254
6284
|
}
|
|
6255
6285
|
if (projectType.length > 1) {
|
|
6256
6286
|
console.log("Generate BOM for project types:", projectType.join(", "));
|
|
6257
|
-
return await createMultiXBom(
|
|
6287
|
+
return await createMultiXBom(path, options);
|
|
6258
6288
|
}
|
|
6259
6289
|
// Use the project type alias to return any singular BOM
|
|
6260
6290
|
if (PROJECT_TYPE_ALIASES["java"].includes(projectType[0])) {
|
|
@@ -6352,7 +6382,7 @@ export async function createBom(path, options) {
|
|
|
6352
6382
|
// In recurse mode return multi-language Bom
|
|
6353
6383
|
// https://github.com/cyclonedx/cdxgen/issues/95
|
|
6354
6384
|
if (options.multiProject) {
|
|
6355
|
-
return await createMultiXBom(
|
|
6385
|
+
return await createMultiXBom(path, options);
|
|
6356
6386
|
}
|
|
6357
6387
|
return await createXBom(path, options);
|
|
6358
6388
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyclonedx/cdxgen",
|
|
3
|
-
"version": "10.8.
|
|
3
|
+
"version": "10.8.2",
|
|
4
4
|
"description": "Creates CycloneDX Software Bill of Materials (SBOM) from source or container image",
|
|
5
5
|
"homepage": "http://github.com/cyclonedx/cdxgen",
|
|
6
6
|
"author": "Prabhu Subramanian <prabhu@appthreat.com>",
|
|
@@ -88,13 +88,13 @@
|
|
|
88
88
|
"optionalDependencies": {
|
|
89
89
|
"@appthreat/atom": "2.0.16",
|
|
90
90
|
"@appthreat/cdx-proto": "1.0.1",
|
|
91
|
-
"@cyclonedx/cdxgen-plugins-bin": "1.6.
|
|
92
|
-
"@cyclonedx/cdxgen-plugins-bin-arm64": "1.6.
|
|
93
|
-
"@cyclonedx/cdxgen-plugins-bin-darwin-amd64": "1.6.
|
|
94
|
-
"@cyclonedx/cdxgen-plugins-bin-darwin-arm64": "1.6.
|
|
95
|
-
"@cyclonedx/cdxgen-plugins-bin-ppc64": "1.6.
|
|
96
|
-
"@cyclonedx/cdxgen-plugins-bin-windows-amd64": "1.6.
|
|
97
|
-
"@cyclonedx/cdxgen-plugins-bin-windows-arm64": "1.6.
|
|
91
|
+
"@cyclonedx/cdxgen-plugins-bin": "1.6.2",
|
|
92
|
+
"@cyclonedx/cdxgen-plugins-bin-arm64": "1.6.2",
|
|
93
|
+
"@cyclonedx/cdxgen-plugins-bin-darwin-amd64": "1.6.2",
|
|
94
|
+
"@cyclonedx/cdxgen-plugins-bin-darwin-arm64": "1.6.2",
|
|
95
|
+
"@cyclonedx/cdxgen-plugins-bin-ppc64": "1.6.2",
|
|
96
|
+
"@cyclonedx/cdxgen-plugins-bin-windows-amd64": "1.6.2",
|
|
97
|
+
"@cyclonedx/cdxgen-plugins-bin-windows-arm64": "1.6.2",
|
|
98
98
|
"body-parser": "^1.20.2",
|
|
99
99
|
"compression": "^1.7.4",
|
|
100
100
|
"connect": "^3.7.0",
|
package/types/display.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../display.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../display.js"],"names":[],"mappings":"AAuWA,iEA0BC;AAED,uDAoBC;AAnYM,mFAmEN;AAQM,iDAkBN;AACM,kDAsBN;AAeM,qDA4BN;AACM,mDA8CN;AACM,wFAuCN;AA4DM,2DA+BN;AAoDM,iDA8BN"}
|
package/types/docker.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../docker.js"],"names":[],"mappings":"AAoDA;;GAEG;AACH,4CA6CC;AAxED,4BAA6C;AAC7C,8CAA+C;AAkFxC,iCAHI,MAAM,WACN,MAAM,iDAehB;AAqBM,6DAmBN;AAgLM,4EAwGN;AAEM,oFAwBN;AAUM;;;;;;;;EAwEN;AAsBM,2DA8KN;AAEM,2EAsFN;AAMM;;;;;;;;;;;;;GAqDN;AAEM;;;;;;;GAqGN;AAMM,
|
|
1
|
+
{"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../docker.js"],"names":[],"mappings":"AAoDA;;GAEG;AACH,4CA6CC;AAxED,4BAA6C;AAC7C,8CAA+C;AAkFxC,iCAHI,MAAM,WACN,MAAM,iDAehB;AAqBM,6DAmBN;AAgLM,4EAwGN;AAEM,oFAwBN;AAUM;;;;;;;;EAwEN;AAsBM,2DA8KN;AAEM,2EAsFN;AAMM;;;;;;;;;;;;;GAqDN;AAEM;;;;;;;GAqGN;AAMM,8DAiIN;AAKM,4EAmGN;AAEM,+EAMN;AAEM,4EAyCN;AAEM,iFA0BN"}
|
package/types/index.d.ts
CHANGED
|
@@ -237,10 +237,10 @@ export function dedupeBom(options: any, components: any[], parentComponent: any,
|
|
|
237
237
|
/**
|
|
238
238
|
* Function to create bom string for all languages
|
|
239
239
|
*
|
|
240
|
-
* @param {string} pathList list of to the project
|
|
240
|
+
* @param {string[]} pathList list of to the project
|
|
241
241
|
* @param {Object} options Parse options from the cli
|
|
242
242
|
*/
|
|
243
|
-
export function createMultiXBom(pathList: string, options: any): Promise<any>;
|
|
243
|
+
export function createMultiXBom(pathList: string[], options: any): Promise<any>;
|
|
244
244
|
/**
|
|
245
245
|
* Function to create bom string for various languages
|
|
246
246
|
*
|
package/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.js"],"names":[],"mappings":"AAovBA;;;;;;;;GAQG;AACH,gFAFW,MAAM,SAchB;AAyUD;;;;;;;GAOG;AACH,mCALW,MAAM,qBAiEhB;AAED;;;;;GAKG;AACH,uCAHW,MAAM;;;;EAKhB;AAED;;;;;GAKG;AACH,sCAHW,MAAM;;;;EAkBhB;AAED;;;;;GAKG;AACH,oCAHW,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.js"],"names":[],"mappings":"AAovBA;;;;;;;;GAQG;AACH,gFAFW,MAAM,SAchB;AAyUD;;;;;;;GAOG;AACH,mCALW,MAAM,qBAiEhB;AAED;;;;;GAKG;AACH,uCAHW,MAAM;;;;EAKhB;AAED;;;;;GAKG;AACH,sCAHW,MAAM;;;;EAkBhB;AAED;;;;;GAKG;AACH,oCAHW,MAAM,8BA0+BhB;AAED;;;;;GAKG;AACH,sCAHW,MAAM,8BA2chB;AAED;;;;;GAKG;AACH,sCAHW,MAAM,8BAsXhB;AAED;;;;;GAKG;AACH,kCAHW,MAAM,8BAkUhB;AAED;;;;;GAKG;AACH,oCAHW,MAAM,8BAqIhB;AAED;;;;;GAKG;AACH,oCAHW,MAAM,8BAiDhB;AAED;;;;;GAKG;AACH,mCAHW,MAAM,qBA+KhB;AAED;;;;;GAKG;AACH,uCAHW,MAAM,qBAsHhB;AAED;;;;;GAKG;AACH,uCAHW,MAAM,qBA2BhB;AAED;;;;;GAKG;AACH,sCAHW,MAAM,qBA2BhB;AAED;;;;;GAKG;AACH,sCAHW,MAAM,qBA2BhB;AAED;;;;;GAKG;AACH,0CAHW,MAAM,qBAuBhB;AAED;;;;;GAKG;AACH,kCAHW,MAAM,8BAqDhB;AAED;;;;;GAKG;AACH,uCAHW,MAAM,8BA4ChB;AAED;;;;;GAKG;AACH,oCAHW,MAAM,qBA2BhB;AAED;;;;;GAKG;AACH,qCAHW,MAAM,8BAwFhB;AAED;;;;;GAKG;AACH,iDAHW,MAAM,qBAiUhB;AAED;;;;;GAKG;AACH,mCAHW,MAAM,qBAwJhB;AAED;;;;;GAKG;AACH,oCAHW,MAAM,8BAmFhB;AAED;;;;;GAKG;AACH,sCAHW,MAAM,8BAyWhB;AAED;;;;;GAKG;AACH,2CAHW,MAAM;;;;;;;;;;;;;;;;;;;;GAoChB;AAED;;;;;;;;KA+DC;AAED;;;;;;GAMG;AACH,yDA2CC;AAED;;;;;;;;;GASG;AACH,2GA6BC;AAED;;;;;GAKG;AACH,0CAHW,MAAM,EAAE,8BAmclB;AAED;;;;;GAKG;AACH,iCAHW,MAAM,8BAiUhB;AAED;;;;;GAKG;AACH,gCAHW,MAAM,qBAsOhB;AAED;;;;;;GAMG;AACH,wDAFY,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,CAAC,CA2FxE"}
|
package/types/utils.d.ts
CHANGED
|
@@ -989,9 +989,10 @@ export function getGradleCommand(srcPath: string, rootPath: string): string;
|
|
|
989
989
|
* Method to split the output produced by Gradle using parallel processing by project
|
|
990
990
|
*
|
|
991
991
|
* @param {string} rawOutput Full output produced by Gradle using parallel processing
|
|
992
|
+
* @param {string[]} relevantTasks The list of gradle tasks whose output need to be considered.
|
|
992
993
|
* @returns {map} Map with subProject names as keys and corresponding dependency task outputs as values.
|
|
993
994
|
*/
|
|
994
|
-
export function splitOutputByGradleProjects(rawOutput: string): map;
|
|
995
|
+
export function splitOutputByGradleProjects(rawOutput: string, relevantTasks: string[]): map;
|
|
995
996
|
/**
|
|
996
997
|
* Method to return the maven command to use.
|
|
997
998
|
*
|
|
@@ -1020,9 +1021,11 @@ export function findAppModules(src: string, language: string, methodology?: stri
|
|
|
1020
1021
|
* @param {string} basePath Base path
|
|
1021
1022
|
* @param {string} reqOrSetupFile Requirements or setup.py file
|
|
1022
1023
|
* @param {string} tempVenvDir Temp venv dir
|
|
1024
|
+
* @param {Object} parentComponent Parent component
|
|
1025
|
+
*
|
|
1023
1026
|
* @returns List of packages from the virtual env
|
|
1024
1027
|
*/
|
|
1025
|
-
export function getPipFrozenTree(basePath: string, reqOrSetupFile: string, tempVenvDir: string): {
|
|
1028
|
+
export function getPipFrozenTree(basePath: string, reqOrSetupFile: string, tempVenvDir: string, parentComponent: any): {
|
|
1026
1029
|
pkgList: {
|
|
1027
1030
|
name: any;
|
|
1028
1031
|
version: any;
|
package/types/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../utils.js"],"names":[],"mappings":"AAsSA;;;;;;GAMG;AACH,mGAkDC;AAgBD;;;;;GAKG;AACH,qCAHW,MAAM,WACN,MAAM,0BAqBhB;AAED;;;;;;GAMG;AACH,+CAJW,MAAM,WACN,MAAM,+BAoBhB;AAYD;;;;GAIG;AACH,gCAFa,MAAM,CAIlB;AAED;;;;;;IAMI;AACJ,iDAJW,MAAM,GACJ,OAAO,CAiBnB;AAED;;;;;;;;GAQG;AACH,iEAoBC;AAED;;;;;GAKG;AACH,6CAmDC;AAED;;;;;;GAMG;AACH,sEA0DC;AAED;;;;GAIG;AACH,4EAoCC;AAED;;;GAGG;AACH;;EAUC;AAED,sEA0BC;AAED;;;;GAIG;AACH,+DA4CC;AAED;;;;;GAKG;AACH,0CAHW,MAAM,WACN,OAAO,kBAkFjB;AAED;;;;;GAKG;AACH,0CAHW,MAAM,YACN,MAAM;;;GAqVhB;AAED;;;;;;;GAOG;AACH,6CAFW,MAAM,MAwDhB;AAwBD;;;;GAIG;AACH,4CAFW,MAAM;;;GAqNhB;AAED;;;;GAIG;AACH,4CAFW,MAAM,kBAiEhB;AA2BD;;;;;GAKG;AACH,wCAHW,MAAM,oBACN,MAAM;;;;;;;;;GA0ZhB;AAED;;;;GAIG;AACH,8CAFW,MAAM,kBA+ChB;AAED;;;;GAIG;AACH,sCAFW,MAAM,kBAgFhB;AAED;;;;GAIG;AACH;;;;;;;;;;;;;;;;;;;;;;IAqDC;AAED;;;;;;GAMG;AACH,0CALW,MAAM,WACN,MAAM,OAgJhB;AAED;;;;;;GAMG;AACH,0CALW,MAAM,qBACN,MAAM,oBACN,MAAM,uBACN,MAAM;;;;;;;;;;;;;;;;EAkNhB;AAED;;;GAGG;AACH,uCAFW,MAAM,SAoChB;AAED;;;GAGG;AACH,wCAFW,MAAM,OAahB;AAED,yEAwBC;AAED;;;;GAIG;AACH,+CAFW,MAAM;;;EA6ChB;AAED;;;;GAIG;AACH,iDAFW,MAAM;;;;;;;;EAsChB;AAED;;;;;;;;GAQG;AACH,qDANW,MAAM,YACN,MAAM,0BAGJ,MAAM,CA2DlB;AAED;;;;;;GAMG;AACH,6CAJW,MAAM,YACN,MAAM,cACN,MAAM,MA0EhB;AAED;;;GAGG;AACH,iDAFW,MAAM,SA4ChB;AAED;;;GAGG;AACH,8CAFW,MAAM,SAsDhB;AAED;;;GAGG;AACH,2CAFW,MAAM,SAiBhB;AAED;;GAEG;AACH,kDAoCC;AAED;;;;GAIG;AACH,oCAFW,MAAM,OAchB;AAED;;;;GAIG;AACH,kDAUC;AAED;;;;;GAKG;AACH,mFAiGC;AAED;;;;;;;;;GASG;AACH,sFAMC;AAED;;;;;;;;;GASG;AACH,gFAFY,MAAO,SAAS,CAwB3B;AAED;;;;;;;;;GASG;AACH,0EAFY,OAAO,QAAQ,CAU1B;AAED;;;;GAIG;AACH,4DAFW,WAAY,SAYtB;AAED;;;;;;;;;GASG;AACH,+FAFY,OAAO,QAAQ,CAc1B;AAED;;;;GAIG;AACH;;;EAqBC;AAED;;;;;GAKG;AACH,iFAFW,GAAC,OA0BX;AAED;;;;;GAKG;AACH,sFAsNC;AAED;;;;GAIG;AACH,qDAmBC;AAED;;;;GAIG;AACH,gEAeC;AAED;;;;GAIG;AACH,6CAFW,MAAM,MAmEhB;AAED;;;;;GAKG;AACH,6DAFW,MAAM;;;;;;;GAqHhB;AAED;;;;;GAKG;AACH,mFAgKC;AAED;;;;;;GAMG;AACH,kCAJW,MAAM;;;;;;;;GA2EhB;AAED;;;;GAIG;AACH,mEAqBC;AAED;;;;GAIG;AACH,+DAFY,SAAO,SAAS,CAc3B;AAED;;;;GAIG;AACH,oDAFY,QAAQ,CASnB;AAED;;;;;GAKG;AACH,oEAFY,SAAO,SAAS,CAc3B;AAED;;;;;;GAMG;AACH,oEAFY,OAAO,QAAQ,CA8D1B;AAED;;;;GAIG;AACH,iEAgDC;AAED,+FA4BC;AAED,8EA2EC;AAED;;;;;GAKG;AACH,0CAHW,MAAM;;;GA0DhB;AA0BD;;;;;;;;;GASG;AACH,2CAPW,MAAM,aACN,MAAM;;;;;;GA6FhB;AAED;;;;GAIG;AACH,yCAHW,MAAM,OAehB;AAED;;;;GAIG;AACH,0CAHW,MAAM,kBAuChB;AAED,+DA+CC;AAED,uEAwBC;AA6BD;;;;GAIG;AACH,oEAmGC;AAED;;;;GAIG;AACH,8CAFW,MAAM,kBAgChB;AAED;;;;;GAKG;AACH,kDAHW,MAAM,YACN,MAAM;;;;;;;;;;;;;;GAuPhB;AAED;;;;GAIG;AACH,kEAoEC;AAED;;;;GAIG;AACH,gEA0DC;AA0BD;;;;;;;;;;;;;;;;;GAiBG;AACH,mEALW,OAAO,4BAiLjB;AAED;;;;;;;;GAQG;AACH,+DALW,OAAO,4BAsIjB;AAED;;;IAwIC;AAED,wEA0BC;AAED,mEAqCC;AAED,0DAkBC;AAED,wDA+DC;AAED,0FAkEC;AAED;;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../utils.js"],"names":[],"mappings":"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"}
|
package/utils.js
CHANGED
|
@@ -6001,8 +6001,7 @@ export function recurseImageNameLookup(keyValueObj, pkgList, imgList) {
|
|
|
6001
6001
|
}
|
|
6002
6002
|
|
|
6003
6003
|
export function parseContainerFile(fileContents) {
|
|
6004
|
-
const
|
|
6005
|
-
|
|
6004
|
+
const imagesSet = new Set();
|
|
6006
6005
|
const buildStageNames = [];
|
|
6007
6006
|
for (let line of fileContents.split("\n")) {
|
|
6008
6007
|
line = line.trim();
|
|
@@ -6012,11 +6011,14 @@ export function parseContainerFile(fileContents) {
|
|
|
6012
6011
|
}
|
|
6013
6012
|
|
|
6014
6013
|
if (line.startsWith("FROM")) {
|
|
6015
|
-
|
|
6014
|
+
// The alias could be called AS or as
|
|
6015
|
+
const fromStatement = line.split("FROM ")[1].split(/\s(as|AS)\s/);
|
|
6016
6016
|
|
|
6017
6017
|
const imageStatement = fromStatement[0].trim();
|
|
6018
|
-
const buildStageName =
|
|
6019
|
-
|
|
6018
|
+
const buildStageName =
|
|
6019
|
+
fromStatement.length > 1
|
|
6020
|
+
? fromStatement[fromStatement.length - 1].trim()
|
|
6021
|
+
: undefined;
|
|
6020
6022
|
if (buildStageNames.includes(imageStatement)) {
|
|
6021
6023
|
if (DEBUG_MODE) {
|
|
6022
6024
|
console.log(
|
|
@@ -6025,10 +6027,7 @@ export function parseContainerFile(fileContents) {
|
|
|
6025
6027
|
}
|
|
6026
6028
|
continue;
|
|
6027
6029
|
}
|
|
6028
|
-
|
|
6029
|
-
imgList.push({
|
|
6030
|
-
image: imageStatement,
|
|
6031
|
-
});
|
|
6030
|
+
imagesSet.add(imageStatement);
|
|
6032
6031
|
|
|
6033
6032
|
if (buildStageName) {
|
|
6034
6033
|
buildStageNames.push(buildStageName);
|
|
@@ -6036,7 +6035,9 @@ export function parseContainerFile(fileContents) {
|
|
|
6036
6035
|
}
|
|
6037
6036
|
}
|
|
6038
6037
|
|
|
6039
|
-
return
|
|
6038
|
+
return Array.from(imagesSet).map((i) => {
|
|
6039
|
+
return { image: i };
|
|
6040
|
+
});
|
|
6040
6041
|
}
|
|
6041
6042
|
|
|
6042
6043
|
export function parseBitbucketPipelinesFile(fileContents) {
|
|
@@ -8953,7 +8954,9 @@ export async function extractJarArchive(jarFile, tempDir, jarNSMapping = {}) {
|
|
|
8953
8954
|
} // for
|
|
8954
8955
|
} // if
|
|
8955
8956
|
if (jarFiles.length !== pkgList.length) {
|
|
8956
|
-
console.log(
|
|
8957
|
+
console.log(
|
|
8958
|
+
`Obtained only ${pkgList.length} components from ${jarFiles.length} jars.`,
|
|
8959
|
+
);
|
|
8957
8960
|
}
|
|
8958
8961
|
return pkgList;
|
|
8959
8962
|
}
|
|
@@ -9199,20 +9202,28 @@ export function getGradleCommand(srcPath, rootPath) {
|
|
|
9199
9202
|
* Method to split the output produced by Gradle using parallel processing by project
|
|
9200
9203
|
*
|
|
9201
9204
|
* @param {string} rawOutput Full output produced by Gradle using parallel processing
|
|
9205
|
+
* @param {string[]} relevantTasks The list of gradle tasks whose output need to be considered.
|
|
9202
9206
|
* @returns {map} Map with subProject names as keys and corresponding dependency task outputs as values.
|
|
9203
9207
|
*/
|
|
9204
9208
|
|
|
9205
|
-
export function splitOutputByGradleProjects(rawOutput) {
|
|
9209
|
+
export function splitOutputByGradleProjects(rawOutput, relevantTasks) {
|
|
9206
9210
|
const outputSplitBySubprojects = new Map();
|
|
9207
9211
|
let subProjectOut = "";
|
|
9208
9212
|
const outSplitByLine = rawOutput.split("\n");
|
|
9209
9213
|
let currentProjectName = "";
|
|
9214
|
+
const regexPatternForRelevantTasks = `.*:(${relevantTasks.join("|")})(?=\s|\r|$)`;
|
|
9215
|
+
const regexForRelevantTasks = new RegExp(regexPatternForRelevantTasks);
|
|
9210
9216
|
for (const [i, line] of outSplitByLine.entries()) {
|
|
9211
|
-
//filter out everything before first
|
|
9217
|
+
//filter out everything before first task output
|
|
9212
9218
|
if (!line.startsWith("> Task :") && subProjectOut === "") {
|
|
9213
9219
|
continue;
|
|
9214
9220
|
}
|
|
9215
9221
|
|
|
9222
|
+
//ignore output of irrelevant tasks
|
|
9223
|
+
if (line.startsWith("> Task :") && !regexForRelevantTasks.test(line)) {
|
|
9224
|
+
continue;
|
|
9225
|
+
}
|
|
9226
|
+
|
|
9216
9227
|
if (line.startsWith("Root project '") || line.startsWith("Project ':")) {
|
|
9217
9228
|
currentProjectName = line.split("'")[1];
|
|
9218
9229
|
currentProjectName = currentProjectName.replace(":", "");
|
|
@@ -9225,7 +9236,6 @@ export function splitOutputByGradleProjects(rawOutput) {
|
|
|
9225
9236
|
}
|
|
9226
9237
|
//if in subproject block, keep appending to string
|
|
9227
9238
|
subProjectOut += `${line}\n`;
|
|
9228
|
-
|
|
9229
9239
|
//if end of last dependencies output block, push to array
|
|
9230
9240
|
if (i === outSplitByLine.length - 1) {
|
|
9231
9241
|
outputSplitBySubprojects.set(currentProjectName, subProjectOut);
|
|
@@ -9522,15 +9532,46 @@ function flattenDeps(dependenciesMap, pkgList, reqOrSetupFile, t) {
|
|
|
9522
9532
|
.sort();
|
|
9523
9533
|
}
|
|
9524
9534
|
|
|
9535
|
+
function get_python_command_from_env(env) {
|
|
9536
|
+
// Virtual environments needs special treatment to use the correct python executable
|
|
9537
|
+
// Without this step, the default python is always used resulting in false positives
|
|
9538
|
+
const python_exe_name = isWin ? "python.exe" : "python";
|
|
9539
|
+
const python3_exe_name = isWin ? "python3.exe" : "python3";
|
|
9540
|
+
let python_cmd_to_use = PYTHON_CMD;
|
|
9541
|
+
if (env.VIRTUAL_ENV) {
|
|
9542
|
+
if (existsSync(join(env.VIRTUAL_ENV, "bin", python_exe_name))) {
|
|
9543
|
+
python_cmd_to_use = join(env.VIRTUAL_ENV, "bin", python_exe_name);
|
|
9544
|
+
} else if (existsSync(join(env.VIRTUAL_ENV, "bin", python3_exe_name))) {
|
|
9545
|
+
python_cmd_to_use = join(env.VIRTUAL_ENV, "bin", python3_exe_name);
|
|
9546
|
+
}
|
|
9547
|
+
} else if (env.CONDA_PREFIX) {
|
|
9548
|
+
if (existsSync(join(env.CONDA_PREFIX, "bin", python_exe_name))) {
|
|
9549
|
+
python_cmd_to_use = join(env.CONDA_PREFIX, "bin", python_exe_name);
|
|
9550
|
+
} else if (existsSync(join(env.CONDA_PREFIX, "bin", python3_exe_name))) {
|
|
9551
|
+
python_cmd_to_use = join(env.CONDA_PREFIX, "bin", python3_exe_name);
|
|
9552
|
+
}
|
|
9553
|
+
} else if (env.CONDA_PYTHON_EXE) {
|
|
9554
|
+
python_cmd_to_use = env.CONDA_PYTHON_EXE;
|
|
9555
|
+
}
|
|
9556
|
+
return python_cmd_to_use;
|
|
9557
|
+
}
|
|
9558
|
+
|
|
9525
9559
|
/**
|
|
9526
9560
|
* Execute pip freeze by creating a virtual env in a temp directory and construct the dependency tree
|
|
9527
9561
|
*
|
|
9528
9562
|
* @param {string} basePath Base path
|
|
9529
9563
|
* @param {string} reqOrSetupFile Requirements or setup.py file
|
|
9530
9564
|
* @param {string} tempVenvDir Temp venv dir
|
|
9565
|
+
* @param {Object} parentComponent Parent component
|
|
9566
|
+
*
|
|
9531
9567
|
* @returns List of packages from the virtual env
|
|
9532
9568
|
*/
|
|
9533
|
-
export function getPipFrozenTree(
|
|
9569
|
+
export function getPipFrozenTree(
|
|
9570
|
+
basePath,
|
|
9571
|
+
reqOrSetupFile,
|
|
9572
|
+
tempVenvDir,
|
|
9573
|
+
parentComponent,
|
|
9574
|
+
) {
|
|
9534
9575
|
const pkgList = [];
|
|
9535
9576
|
const formulationList = [];
|
|
9536
9577
|
const rootList = [];
|
|
@@ -9682,6 +9723,9 @@ export function getPipFrozenTree(basePath, reqOrSetupFile, tempVenvDir) {
|
|
|
9682
9723
|
}
|
|
9683
9724
|
}
|
|
9684
9725
|
} else {
|
|
9726
|
+
// We are about to do a pip install with the right python command from the virtual environment
|
|
9727
|
+
// This step can fail if the correct OS packages and development libraries are not installed
|
|
9728
|
+
const python_cmd_for_tree = get_python_command_from_env(env);
|
|
9685
9729
|
let pipInstallArgs = [
|
|
9686
9730
|
"-m",
|
|
9687
9731
|
"pip",
|
|
@@ -9704,8 +9748,11 @@ export function getPipFrozenTree(basePath, reqOrSetupFile, tempVenvDir) {
|
|
|
9704
9748
|
const addArgs = process.env.PIP_INSTALL_ARGS.split(" ");
|
|
9705
9749
|
pipInstallArgs = pipInstallArgs.concat(addArgs);
|
|
9706
9750
|
}
|
|
9751
|
+
if (DEBUG_MODE) {
|
|
9752
|
+
console.log("Executing", python_cmd_for_tree, pipInstallArgs.join(" "));
|
|
9753
|
+
}
|
|
9707
9754
|
// Attempt to perform pip install
|
|
9708
|
-
result = spawnSync(
|
|
9755
|
+
result = spawnSync(python_cmd_for_tree, pipInstallArgs, {
|
|
9709
9756
|
cwd: basePath,
|
|
9710
9757
|
encoding: "utf-8",
|
|
9711
9758
|
timeout: TIMEOUT_MS,
|
|
@@ -9774,8 +9821,12 @@ export function getPipFrozenTree(basePath, reqOrSetupFile, tempVenvDir) {
|
|
|
9774
9821
|
`About to construct the pip dependency tree based on ${reqOrSetupFile}. Please wait ...`,
|
|
9775
9822
|
);
|
|
9776
9823
|
}
|
|
9824
|
+
const python_cmd_for_tree = get_python_command_from_env(env);
|
|
9825
|
+
if (DEBUG_MODE) {
|
|
9826
|
+
console.log(`Using the python executable ${python_cmd_for_tree}`);
|
|
9827
|
+
}
|
|
9777
9828
|
// This is a slow step that ideally needs to be invoked only once per venv
|
|
9778
|
-
const tree = getTreeWithPlugin(env,
|
|
9829
|
+
const tree = getTreeWithPlugin(env, python_cmd_for_tree, basePath);
|
|
9779
9830
|
if (DEBUG_MODE && !tree.length) {
|
|
9780
9831
|
console.log(
|
|
9781
9832
|
"Dependency tree generation has failed. Please check for any errors or version incompatibilities reported in the logs.",
|
|
@@ -9784,6 +9835,17 @@ export function getPipFrozenTree(basePath, reqOrSetupFile, tempVenvDir) {
|
|
|
9784
9835
|
const dependenciesMap = {};
|
|
9785
9836
|
for (const t of tree) {
|
|
9786
9837
|
const name = t.name.replace(/_/g, "-").toLowerCase();
|
|
9838
|
+
// Bug #1232 - the root package might lack a version resulting in duplicate tree
|
|
9839
|
+
// So we make use of the existing parent component to try and patch the version
|
|
9840
|
+
if (
|
|
9841
|
+
parentComponent &&
|
|
9842
|
+
parentComponent.name === t.name &&
|
|
9843
|
+
parentComponent.version &&
|
|
9844
|
+
parentComponent?.version !== "latest" &&
|
|
9845
|
+
t.version === "latest"
|
|
9846
|
+
) {
|
|
9847
|
+
t.version = parentComponent.version;
|
|
9848
|
+
}
|
|
9787
9849
|
const version = t.version;
|
|
9788
9850
|
const scope = PYTHON_EXCLUDED_COMPONENTS.includes(name)
|
|
9789
9851
|
? "excluded"
|
|
@@ -11053,6 +11115,17 @@ export function addEvidenceForDotnet(pkgList, slicesFile) {
|
|
|
11053
11115
|
}
|
|
11054
11116
|
}
|
|
11055
11117
|
}
|
|
11118
|
+
if (slicesData.AssemblyInformation) {
|
|
11119
|
+
for (const apkg of pkgList) {
|
|
11120
|
+
if (!apkg.version) {
|
|
11121
|
+
for (const assemblyInfo of slicesData.AssemblyInformation) {
|
|
11122
|
+
if (apkg.name === assemblyInfo.Name) {
|
|
11123
|
+
apkg.version = assemblyInfo.Version;
|
|
11124
|
+
}
|
|
11125
|
+
}
|
|
11126
|
+
}
|
|
11127
|
+
}
|
|
11128
|
+
}
|
|
11056
11129
|
}
|
|
11057
11130
|
if (Object.keys(purlLocationMap).length) {
|
|
11058
11131
|
for (const apkg of pkgList) {
|
package/utils.test.js
CHANGED
|
@@ -165,8 +165,10 @@ test("splits parallel gradle properties output correctly", () => {
|
|
|
165
165
|
"./test/gradle-prop-parallel.out",
|
|
166
166
|
{ encoding: "utf-8" },
|
|
167
167
|
);
|
|
168
|
+
const relevantTasks = ["properties"];
|
|
168
169
|
const propOutputSplitBySubProject = splitOutputByGradleProjects(
|
|
169
170
|
parallelGradlePropertiesOutput,
|
|
171
|
+
relevantTasks,
|
|
170
172
|
);
|
|
171
173
|
|
|
172
174
|
expect(propOutputSplitBySubProject.size).toEqual(4);
|
|
@@ -195,8 +197,10 @@ test("splits parallel gradle dependencies output correctly", () => {
|
|
|
195
197
|
"./test/gradle-dep-parallel.out",
|
|
196
198
|
{ encoding: "utf-8" },
|
|
197
199
|
);
|
|
200
|
+
const relevantTasks = ["dependencies"];
|
|
198
201
|
const depOutputSplitBySubProject = splitOutputByGradleProjects(
|
|
199
202
|
parallelGradleDepOutput,
|
|
203
|
+
relevantTasks,
|
|
200
204
|
);
|
|
201
205
|
|
|
202
206
|
expect(depOutputSplitBySubProject.size).toEqual(4);
|
|
@@ -218,6 +222,41 @@ test("splits parallel gradle dependencies output correctly", () => {
|
|
|
218
222
|
expect(retMap.dependenciesList.length).toEqual(13);
|
|
219
223
|
});
|
|
220
224
|
|
|
225
|
+
test("splits parallel custom gradle task outputs correctly", () => {
|
|
226
|
+
const parallelGradleOutputWithOverridenTask = readFileSync(
|
|
227
|
+
"./test/gradle-build-env-dep.out",
|
|
228
|
+
{ encoding: "utf-8" },
|
|
229
|
+
);
|
|
230
|
+
const overridenTasks = ["buildEnvironment"];
|
|
231
|
+
const customDepTaskOuputSplitByProject = splitOutputByGradleProjects(
|
|
232
|
+
parallelGradleOutputWithOverridenTask,
|
|
233
|
+
overridenTasks,
|
|
234
|
+
);
|
|
235
|
+
expect(customDepTaskOuputSplitByProject.size).toEqual(4);
|
|
236
|
+
expect(customDepTaskOuputSplitByProject.has("dependency-diff-check")).toBe(
|
|
237
|
+
true,
|
|
238
|
+
);
|
|
239
|
+
expect(
|
|
240
|
+
customDepTaskOuputSplitByProject.has("dependency-diff-check-service"),
|
|
241
|
+
).toBe(true);
|
|
242
|
+
expect(
|
|
243
|
+
customDepTaskOuputSplitByProject.has("dependency-diff-check-common-core"),
|
|
244
|
+
).toBe(true);
|
|
245
|
+
expect(
|
|
246
|
+
customDepTaskOuputSplitByProject.has(
|
|
247
|
+
"dependency-diff-check-client-starter",
|
|
248
|
+
),
|
|
249
|
+
).toBe(true);
|
|
250
|
+
|
|
251
|
+
const retMap = parseGradleDep(
|
|
252
|
+
customDepTaskOuputSplitByProject.get(
|
|
253
|
+
"dependency-diff-check-client-starter",
|
|
254
|
+
),
|
|
255
|
+
);
|
|
256
|
+
expect(retMap.pkgList.length).toEqual(22);
|
|
257
|
+
expect(retMap.dependenciesList.length).toEqual(23);
|
|
258
|
+
});
|
|
259
|
+
|
|
221
260
|
test("parse gradle dependencies", () => {
|
|
222
261
|
expect(parseGradleDep(null)).toEqual({});
|
|
223
262
|
let parsedList = parseGradleDep(
|
|
@@ -3764,23 +3803,17 @@ test("parse containerfiles / dockerfiles", () => {
|
|
|
3764
3803
|
const dep_list = parseContainerFile(
|
|
3765
3804
|
readFileSync("./test/data/Dockerfile", { encoding: "utf-8" }),
|
|
3766
3805
|
);
|
|
3767
|
-
expect(dep_list.length).toEqual(
|
|
3768
|
-
expect(dep_list[0]).toEqual({
|
|
3769
|
-
image: "hello-world",
|
|
3770
|
-
});
|
|
3806
|
+
expect(dep_list.length).toEqual(4);
|
|
3771
3807
|
expect(dep_list[0]).toEqual({
|
|
3772
3808
|
image: "hello-world",
|
|
3773
3809
|
});
|
|
3774
3810
|
expect(dep_list[1]).toEqual({
|
|
3775
|
-
image: "hello-world",
|
|
3776
|
-
});
|
|
3777
|
-
expect(dep_list[2]).toEqual({
|
|
3778
3811
|
image: "hello-world:latest",
|
|
3779
3812
|
});
|
|
3780
|
-
expect(dep_list[
|
|
3813
|
+
expect(dep_list[2]).toEqual({
|
|
3781
3814
|
image: "hello-world@sha256:1234567890abcdef",
|
|
3782
3815
|
});
|
|
3783
|
-
expect(dep_list[
|
|
3816
|
+
expect(dep_list[3]).toEqual({
|
|
3784
3817
|
image: "hello-world:latest@sha256:1234567890abcdef",
|
|
3785
3818
|
});
|
|
3786
3819
|
});
|