@cyclonedx/cdxgen 12.1.3 → 12.1.5
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 +1 -1
- package/bin/cdxgen.js +12 -0
- package/bin/repl.js +2 -2
- package/lib/cli/index.js +164 -71
- package/lib/evinser/evinser.js +3 -4
- package/lib/evinser/swiftsem.js +1 -1
- package/lib/helpers/caxa.js +1 -1
- package/lib/helpers/display.js +6 -10
- package/lib/helpers/envcontext.js +5 -5
- package/lib/helpers/pythonutils.js +296 -0
- package/lib/helpers/pythonutils.poku.js +469 -0
- package/lib/helpers/utils.js +303 -95
- package/lib/helpers/utils.poku.js +84 -1
- package/lib/managers/piptree.js +1 -1
- package/lib/parsers/npmrc.js +88 -0
- package/lib/parsers/npmrc.poku.js +492 -0
- package/lib/server/openapi.yaml +0 -9
- package/lib/server/server.js +18 -5
- package/lib/stages/pregen/env-audit.js +34 -0
- package/lib/stages/pregen/env-audit.poku.js +290 -0
- package/lib/third-party/arborist/lib/deepest-nesting-target.js +1 -1
- package/lib/third-party/arborist/lib/node.js +3 -3
- package/lib/third-party/arborist/lib/shrinkwrap.js +1 -1
- package/lib/third-party/arborist/lib/tree-check.js +1 -1
- package/package.json +6 -6
- package/types/lib/cli/index.d.ts +39 -39
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +19 -19
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/evinser/swiftsem.d.ts +14 -14
- package/types/lib/evinser/swiftsem.d.ts.map +1 -1
- package/types/lib/helpers/cbomutils.d.ts +1 -1
- package/types/lib/helpers/cbomutils.d.ts.map +1 -1
- package/types/lib/helpers/db.d.ts +2 -2
- package/types/lib/helpers/db.d.ts.map +1 -1
- package/types/lib/helpers/display.d.ts +2 -2
- package/types/lib/helpers/display.d.ts.map +1 -1
- package/types/lib/helpers/envcontext.d.ts +14 -14
- package/types/lib/helpers/envcontext.d.ts.map +1 -1
- package/types/lib/helpers/logger.d.ts +1 -1
- package/types/lib/helpers/logger.d.ts.map +1 -1
- package/types/lib/helpers/protobom.d.ts +4 -2
- package/types/lib/helpers/protobom.d.ts.map +1 -1
- package/types/lib/helpers/pythonutils.d.ts +9 -0
- package/types/lib/helpers/pythonutils.d.ts.map +1 -0
- package/types/lib/helpers/utils.d.ts +103 -88
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +2 -2
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +2 -2
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/managers/oci.d.ts +1 -1
- package/types/lib/managers/oci.d.ts.map +1 -1
- package/types/lib/managers/piptree.d.ts +1 -1
- package/types/lib/managers/piptree.d.ts.map +1 -1
- package/types/lib/parsers/iri.d.ts +6 -6
- package/types/lib/parsers/iri.d.ts.map +1 -1
- package/types/lib/parsers/npmrc.d.ts +23 -0
- package/types/lib/parsers/npmrc.d.ts.map +1 -0
- package/types/lib/server/server.d.ts +1 -1
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/annotator.d.ts +3 -3
- package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts +5 -5
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/pregen/env-audit.d.ts +2 -0
- package/types/lib/stages/pregen/env-audit.d.ts.map +1 -0
- package/types/lib/stages/pregen/pregen.d.ts +6 -6
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/arborist/index.d.ts +4 -3
- package/types/lib/third-party/arborist/lib/arborist/index.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/can-place-dep.d.ts +5 -5
- package/types/lib/third-party/arborist/lib/can-place-dep.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/case-insensitive-map.d.ts +4 -4
- package/types/lib/third-party/arborist/lib/case-insensitive-map.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/diff.d.ts +3 -3
- package/types/lib/third-party/arborist/lib/diff.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/edge.d.ts +2 -2
- package/types/lib/third-party/arborist/lib/edge.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/gather-dep-set.d.ts +1 -1
- package/types/lib/third-party/arborist/lib/gather-dep-set.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/inventory.d.ts +3 -2
- package/types/lib/third-party/arborist/lib/inventory.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/link.d.ts +10 -7
- package/types/lib/third-party/arborist/lib/link.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/node.d.ts +8 -8
- package/types/lib/third-party/arborist/lib/node.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/optional-set.d.ts +1 -1
- package/types/lib/third-party/arborist/lib/optional-set.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/override-set.d.ts +3 -3
- package/types/lib/third-party/arborist/lib/override-set.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/peer-entry-sets.d.ts +1 -1
- package/types/lib/third-party/arborist/lib/peer-entry-sets.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/place-dep.d.ts +3 -3
- package/types/lib/third-party/arborist/lib/place-dep.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/shrinkwrap.d.ts +7 -7
- package/types/lib/third-party/arborist/lib/shrinkwrap.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/version-from-tgz.d.ts +1 -1
- package/types/lib/third-party/arborist/lib/version-from-tgz.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/yarn-lock.d.ts +4 -3
- package/types/lib/third-party/arborist/lib/yarn-lock.d.ts.map +1 -1
- package/types/lib/third-party/arborist/lib/arborist/load-actual.d.ts +0 -34
- package/types/lib/third-party/arborist/lib/arborist/load-actual.d.ts.map +0 -1
- package/types/lib/third-party/arborist/lib/arborist/load-virtual.d.ts +0 -24
- package/types/lib/third-party/arborist/lib/arborist/load-virtual.d.ts.map +0 -1
- package/types/lib/third-party/arborist/lib/tracker.d.ts +0 -13
- package/types/lib/third-party/arborist/lib/tracker.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -104,7 +104,7 @@ docker run --rm -e CDXGEN_DEBUG_MODE=debug -v /tmp:/tmp -v $(pwd):/app:rw -t ghc
|
|
|
104
104
|
In deno applications, cdxgen could be directly imported without any conversion. Please see the section on [integration as a library](#integration-as-library)
|
|
105
105
|
|
|
106
106
|
```ts
|
|
107
|
-
import { createBom, submitBom } from "npm:@cyclonedx/cdxgen@^
|
|
107
|
+
import { createBom, submitBom } from "npm:@cyclonedx/cdxgen@^12.1.0";
|
|
108
108
|
```
|
|
109
109
|
|
|
110
110
|
## Getting Help
|
package/bin/cdxgen.js
CHANGED
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
} from "../lib/helpers/utils.js";
|
|
43
43
|
import { validateBom } from "../lib/helpers/validator.js";
|
|
44
44
|
import { postProcess } from "../lib/stages/postgen/postgen.js";
|
|
45
|
+
import { auditEnvironment } from "../lib/stages/pregen/env-audit.js";
|
|
45
46
|
import { prepareEnv } from "../lib/stages/pregen/pregen.js";
|
|
46
47
|
|
|
47
48
|
// Support for config files
|
|
@@ -840,6 +841,17 @@ const needsBomSigning = ({ generateKeyAndSign }) =>
|
|
|
840
841
|
(async () => {
|
|
841
842
|
// Display the sponsor banner
|
|
842
843
|
printSponsorBanner(options);
|
|
844
|
+
// Our quest to audit and check the SBOM generation environment to prevent our users from getting exploited
|
|
845
|
+
// during SBOM generation.
|
|
846
|
+
const envWarnings = auditEnvironment();
|
|
847
|
+
if (envWarnings?.length) {
|
|
848
|
+
for (const w of envWarnings) {
|
|
849
|
+
console.log(`SECURE MODE: ${w}`);
|
|
850
|
+
}
|
|
851
|
+
if (isSecureMode) {
|
|
852
|
+
process.exit(1);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
843
855
|
// Start SBOM server
|
|
844
856
|
if (options.server) {
|
|
845
857
|
const serverModule = await import("../lib/server/server.js");
|
package/bin/repl.js
CHANGED
|
@@ -594,7 +594,7 @@ cdxgenRepl.defineCommand("osinfocategories", {
|
|
|
594
594
|
cdxgenRepl.defineCommand("licenses", {
|
|
595
595
|
help: "visualize license distribution",
|
|
596
596
|
async action() {
|
|
597
|
-
if (!sbom
|
|
597
|
+
if (!sbom?.components) {
|
|
598
598
|
console.log("⚠ No SBOM loaded.");
|
|
599
599
|
this.displayPrompt();
|
|
600
600
|
return;
|
|
@@ -649,7 +649,7 @@ cdxgenRepl.defineCommand("inspect", {
|
|
|
649
649
|
cdxgenRepl.defineCommand("tagcloud", {
|
|
650
650
|
help: "generate a text/tag cloud based on component descriptions and tags",
|
|
651
651
|
action() {
|
|
652
|
-
if (!sbom
|
|
652
|
+
if (!sbom?.components) {
|
|
653
653
|
console.log("⚠ No SBOM loaded.");
|
|
654
654
|
this.displayPrompt();
|
|
655
655
|
return;
|
package/lib/cli/index.js
CHANGED
|
@@ -28,6 +28,7 @@ import { parseCaxaMetadata } from "../helpers/caxa.js";
|
|
|
28
28
|
import { collectOSCryptoLibs } from "../helpers/cbomutils.js";
|
|
29
29
|
import {
|
|
30
30
|
collectEnvInfo,
|
|
31
|
+
GIT_COMMAND,
|
|
31
32
|
getBranch,
|
|
32
33
|
getOriginUrl,
|
|
33
34
|
gitTreeHashes,
|
|
@@ -188,6 +189,7 @@ import {
|
|
|
188
189
|
getPkgPathList,
|
|
189
190
|
parseImageName,
|
|
190
191
|
} from "../managers/docker.js";
|
|
192
|
+
import { DEFAULT_NPMRC_BLOCKLIST, parseNpmrc } from "../parsers/npmrc.js";
|
|
191
193
|
|
|
192
194
|
const dirName = dirNameStr;
|
|
193
195
|
|
|
@@ -2879,17 +2881,17 @@ export async function createNodejsBom(path, options) {
|
|
|
2879
2881
|
);
|
|
2880
2882
|
const npmInstallCount =
|
|
2881
2883
|
Number.parseInt(process.env.NPM_INSTALL_COUNT, 10) || 2;
|
|
2884
|
+
let anyInstallSuccess = false;
|
|
2882
2885
|
// Automatic npm install logic.
|
|
2883
2886
|
// Only perform npm install for smaller projects (< 2 package.json) without the correct number of lock files
|
|
2884
2887
|
if (
|
|
2885
2888
|
(pkgJsonLockFiles?.length === 0 ||
|
|
2886
|
-
pkgJsonLockFiles?.length < pkgJsonFiles?.length) &&
|
|
2889
|
+
pkgJsonLockFiles?.length < pkgJsonFiles?.length - 1) &&
|
|
2887
2890
|
yarnLockFiles?.length === 0 &&
|
|
2888
2891
|
pnpmLockFiles?.length === 0 &&
|
|
2889
2892
|
pkgJsonFiles?.length <= npmInstallCount &&
|
|
2890
2893
|
options.installDeps
|
|
2891
2894
|
) {
|
|
2892
|
-
let anyInstallSuccess = false;
|
|
2893
2895
|
for (const apkgJson of pkgJsonFiles) {
|
|
2894
2896
|
let pkgMgr = "npm";
|
|
2895
2897
|
const supPkgMgrs = ["npm", "yarn", "yarnpkg", "pnpm", "pnpx"];
|
|
@@ -2930,21 +2932,58 @@ export async function createNodejsBom(path, options) {
|
|
|
2930
2932
|
process.env[`${pkgMgr.toUpperCase()}_INSTALL_ARGS`].split(" ");
|
|
2931
2933
|
installArgs = installArgs.concat(addArgs);
|
|
2932
2934
|
}
|
|
2933
|
-
|
|
2935
|
+
// Always invoke the install command with ignore-scripts to guard against version spoofing
|
|
2936
|
+
if (["npm", "pnpm", "yarn"].includes(pkgMgr)) {
|
|
2934
2937
|
if (!installArgs.includes("--ignore-scripts")) {
|
|
2935
2938
|
installArgs.push("--ignore-scripts");
|
|
2936
2939
|
}
|
|
2937
|
-
if (
|
|
2938
|
-
installArgs.push("--
|
|
2940
|
+
if (pkgMgr === "pnpm") {
|
|
2941
|
+
installArgs.push("--ignore-pnpmfile");
|
|
2939
2942
|
}
|
|
2943
|
+
if (pkgMgr === "npm") {
|
|
2944
|
+
for (const c of ["--no-audit", "--no-bin-links"]) {
|
|
2945
|
+
if (!installArgs.includes(c)) {
|
|
2946
|
+
installArgs.push(c);
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
installArgs.push(`--git=${GIT_COMMAND}`);
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
if (
|
|
2953
|
+
pkgMgr === "npm" &&
|
|
2954
|
+
isSecureMode &&
|
|
2955
|
+
!installArgs.join(" ").includes("--allow-git")
|
|
2956
|
+
) {
|
|
2957
|
+
console.log(
|
|
2958
|
+
"Consider passing '--allow-git=none' via the environment variable NPM_INSTALL_ARGS to prevent any git dependencies from being fetched and installed via npm.",
|
|
2959
|
+
);
|
|
2940
2960
|
}
|
|
2941
2961
|
const basePath = dirname(apkgJson);
|
|
2962
|
+
let npmrcData;
|
|
2963
|
+
if (safeExistsSync(join(basePath, ".npmrc"))) {
|
|
2964
|
+
thoughtLog(
|
|
2965
|
+
"Wait, there is a .npmrc file here! I'm going to check if it has anything malicious.",
|
|
2966
|
+
);
|
|
2967
|
+
npmrcData = readFileSync(join(basePath, ".npmrc"), "utf-8");
|
|
2968
|
+
const npmrcObj = parseNpmrc(npmrcData);
|
|
2969
|
+
for (const [key, value] of Object.entries(npmrcObj)) {
|
|
2970
|
+
const baseKey = key.replace(/^(?:\/\/[^/]+\/|@[^:]+:)/, "");
|
|
2971
|
+
if (
|
|
2972
|
+
DEFAULT_NPMRC_BLOCKLIST.has(baseKey) ||
|
|
2973
|
+
DEFAULT_NPMRC_BLOCKLIST.has(key)
|
|
2974
|
+
) {
|
|
2975
|
+
console.warn(
|
|
2976
|
+
`\x1b[1;35mSECURE MODE: Dangerous configuration ${key}=${value} detected in .npmrc! Verify if this is a trusted project. Remove this setting or any other problematic configurations to proceed.\x1b[0m`,
|
|
2977
|
+
);
|
|
2978
|
+
process.exit(1);
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
}
|
|
2942
2982
|
// juice-shop mode
|
|
2943
2983
|
// Projects such as juice-shop prevent lockfile creations using .npmrc files
|
|
2944
2984
|
// Plus, they might require specific npm install args such as --legacy-peer-deps that could lead to strange node_modules structure
|
|
2945
2985
|
// To keep life simple, let's look for any .npmrc file that has package-lock=false to toggle before npm install
|
|
2946
|
-
if (pkgMgr === "npm"
|
|
2947
|
-
const npmrcData = readFileSync(join(basePath, ".npmrc"));
|
|
2986
|
+
if (pkgMgr === "npm") {
|
|
2948
2987
|
if (
|
|
2949
2988
|
npmrcData?.includes("package-lock=false") &&
|
|
2950
2989
|
!installArgs.includes("--package-lock")
|
|
@@ -2962,6 +3001,9 @@ export async function createNodejsBom(path, options) {
|
|
|
2962
3001
|
`**PACKAGE MANAGER**: Let's run the '${pkgMgr}' command with the arguments '${installArgs.join(" ")}' to generate the needed lock files.`,
|
|
2963
3002
|
);
|
|
2964
3003
|
}
|
|
3004
|
+
console.warn(
|
|
3005
|
+
"\x1b[1;35mNotice: Generating an SBOM without a lockfile is risky and non-deterministic. Consider generating and committing the lockfile to your repository to ensure reproducible builds and SBOMs.\x1b[0m",
|
|
3006
|
+
);
|
|
2965
3007
|
console.log(
|
|
2966
3008
|
`Executing '${pkgMgr} ${installArgs.join(" ")}' in`,
|
|
2967
3009
|
basePath,
|
|
@@ -3235,6 +3277,11 @@ export async function createNodejsBom(path, options) {
|
|
|
3235
3277
|
pkgLockFiles?.length &&
|
|
3236
3278
|
isPackageManagerAllowed("npm", ["pnpm", "yarn"], options)
|
|
3237
3279
|
) {
|
|
3280
|
+
if (anyInstallSuccess) {
|
|
3281
|
+
thoughtLog(
|
|
3282
|
+
`I have ${pkgLockFiles.length} package-lock.json file(s) now after a successful npm install.`,
|
|
3283
|
+
);
|
|
3284
|
+
}
|
|
3238
3285
|
manifestFiles = manifestFiles.concat(pkgLockFiles);
|
|
3239
3286
|
for (const f of pkgLockFiles) {
|
|
3240
3287
|
if (DEBUG_MODE) {
|
|
@@ -3844,7 +3891,6 @@ export async function createPythonBom(path, options) {
|
|
|
3844
3891
|
console.log(`Parsing ${f}`);
|
|
3845
3892
|
}
|
|
3846
3893
|
let retMap = await parsePyLockData(lockData, f);
|
|
3847
|
-
// Should we exit for workspace errors
|
|
3848
3894
|
if (retMap?.workspaceWarningShown) {
|
|
3849
3895
|
options.failOnError && process.exit(1);
|
|
3850
3896
|
}
|
|
@@ -3852,7 +3898,6 @@ export async function createPythonBom(path, options) {
|
|
|
3852
3898
|
pkgList = pkgList.concat(retMap.pkgList);
|
|
3853
3899
|
pkgList = trimComponents(pkgList);
|
|
3854
3900
|
}
|
|
3855
|
-
// Retain the parent hierarchy
|
|
3856
3901
|
if (retMap?.parentComponent?.components?.length) {
|
|
3857
3902
|
if (!parentComponent.components) {
|
|
3858
3903
|
parentComponent.components = [];
|
|
@@ -3868,36 +3913,81 @@ export async function createPythonBom(path, options) {
|
|
|
3868
3913
|
parentComponent,
|
|
3869
3914
|
);
|
|
3870
3915
|
}
|
|
3871
|
-
// Retrieve the tree using virtualenv in deep mode and as a fallback
|
|
3872
|
-
// This is a slow operation
|
|
3873
3916
|
if ((options.deep || !dependencies.length) && !f.endsWith("uv.lock")) {
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
formulationList = formulationList.concat(retMap.formulationList);
|
|
3880
|
-
}
|
|
3881
|
-
if (retMap.dependenciesList) {
|
|
3882
|
-
dependencies = mergeDependencies(
|
|
3883
|
-
dependencies,
|
|
3884
|
-
retMap.dependenciesList,
|
|
3917
|
+
if (options.installDeps) {
|
|
3918
|
+
retMap = await getPipFrozenTree(
|
|
3919
|
+
basePath,
|
|
3920
|
+
f,
|
|
3921
|
+
tempDir,
|
|
3885
3922
|
parentComponent,
|
|
3886
3923
|
);
|
|
3924
|
+
if (retMap.pkgList?.length) pkgList = pkgList.concat(retMap.pkgList);
|
|
3925
|
+
if (retMap.formulationList?.length)
|
|
3926
|
+
formulationList = formulationList.concat(retMap.formulationList);
|
|
3927
|
+
if (retMap.dependenciesList)
|
|
3928
|
+
dependencies = mergeDependencies(
|
|
3929
|
+
dependencies,
|
|
3930
|
+
retMap.dependenciesList,
|
|
3931
|
+
parentComponent,
|
|
3932
|
+
);
|
|
3933
|
+
if (retMap.rootList) {
|
|
3934
|
+
const parentDependsOn = new Set();
|
|
3935
|
+
for (const p of retMap.rootList)
|
|
3936
|
+
parentDependsOn.add(
|
|
3937
|
+
`pkg:pypi/${p.name.toLowerCase()}@${p.version}`,
|
|
3938
|
+
);
|
|
3939
|
+
dependencies.splice(0, 0, {
|
|
3940
|
+
ref: parentComponent["bom-ref"],
|
|
3941
|
+
dependsOn: [...parentDependsOn].sort(),
|
|
3942
|
+
});
|
|
3943
|
+
}
|
|
3944
|
+
} else {
|
|
3945
|
+
let exportedReqs = "";
|
|
3946
|
+
if (f.endsWith("poetry.lock")) {
|
|
3947
|
+
thoughtLog(
|
|
3948
|
+
"Using poetry export as a safe, static alternative to pip install.",
|
|
3949
|
+
);
|
|
3950
|
+
const expCmd = safeSpawnSync(
|
|
3951
|
+
"poetry",
|
|
3952
|
+
["export", "-f", "requirements.txt"],
|
|
3953
|
+
{ cwd: basePath, shell: false },
|
|
3954
|
+
);
|
|
3955
|
+
if (expCmd.status === 0 && expCmd.stdout)
|
|
3956
|
+
exportedReqs = expCmd.stdout.toString();
|
|
3957
|
+
} else if (f.endsWith("pdm.lock")) {
|
|
3958
|
+
thoughtLog(
|
|
3959
|
+
"Using pdm export as a safe, static alternative to pip install.",
|
|
3960
|
+
);
|
|
3961
|
+
const expCmd = safeSpawnSync(
|
|
3962
|
+
"pdm",
|
|
3963
|
+
["export", "-f", "requirements"],
|
|
3964
|
+
{ cwd: basePath, shell: false },
|
|
3965
|
+
);
|
|
3966
|
+
if (expCmd.status === 0 && expCmd.stdout)
|
|
3967
|
+
exportedReqs = expCmd.stdout.toString();
|
|
3968
|
+
}
|
|
3969
|
+
if (exportedReqs) {
|
|
3970
|
+
const tmpReqFile = join(
|
|
3971
|
+
tempDir,
|
|
3972
|
+
`exported-${basename(basePath)}-reqs.txt`,
|
|
3973
|
+
);
|
|
3974
|
+
writeFileSync(tmpReqFile, exportedReqs);
|
|
3975
|
+
const dlist = await parseReqFile(tmpReqFile, false);
|
|
3976
|
+
if (dlist?.length) {
|
|
3977
|
+
pkgList = pkgList.concat(dlist);
|
|
3978
|
+
const parentDependsOn = new Set();
|
|
3979
|
+
for (const p of dlist)
|
|
3980
|
+
parentDependsOn.add(
|
|
3981
|
+
`pkg:pypi/${p.name.toLowerCase()}@${p.version}`,
|
|
3982
|
+
);
|
|
3983
|
+
dependencies.splice(0, 0, {
|
|
3984
|
+
ref: parentComponent["bom-ref"],
|
|
3985
|
+
dependsOn: [...parentDependsOn].sort(),
|
|
3986
|
+
});
|
|
3987
|
+
}
|
|
3988
|
+
}
|
|
3887
3989
|
}
|
|
3888
3990
|
}
|
|
3889
|
-
if (retMap.rootList) {
|
|
3890
|
-
const parentDependsOn = new Set();
|
|
3891
|
-
// Complete the dependency tree by making parent component depend on the first level
|
|
3892
|
-
for (const p of retMap.rootList) {
|
|
3893
|
-
parentDependsOn.add(`pkg:pypi/${p.name.toLowerCase()}@${p.version}`);
|
|
3894
|
-
}
|
|
3895
|
-
const pdependencies = {
|
|
3896
|
-
ref: parentComponent["bom-ref"],
|
|
3897
|
-
dependsOn: [...parentDependsOn].sort(),
|
|
3898
|
-
};
|
|
3899
|
-
dependencies.splice(0, 0, pdependencies);
|
|
3900
|
-
}
|
|
3901
3991
|
}
|
|
3902
3992
|
options.parentComponent = parentComponent;
|
|
3903
3993
|
} // poetryMode
|
|
@@ -3915,7 +4005,7 @@ export async function createPythonBom(path, options) {
|
|
|
3915
4005
|
for (const wf of whlFiles) {
|
|
3916
4006
|
const mData = await readZipEntry(wf, "METADATA");
|
|
3917
4007
|
if (mData) {
|
|
3918
|
-
const dlist = parseBdistMetadata(
|
|
4008
|
+
const dlist = parseBdistMetadata(join(wf, "METADATA"), mData);
|
|
3919
4009
|
if (dlist?.length) {
|
|
3920
4010
|
pkgList = pkgList.concat(dlist);
|
|
3921
4011
|
}
|
|
@@ -3997,29 +4087,29 @@ export async function createPythonBom(path, options) {
|
|
|
3997
4087
|
for (const f of reqFiles) {
|
|
3998
4088
|
const basePath = dirname(f);
|
|
3999
4089
|
if (options.installDeps) {
|
|
4000
|
-
const
|
|
4090
|
+
const rpkgMap = await getPipFrozenTree(
|
|
4001
4091
|
basePath,
|
|
4002
4092
|
f,
|
|
4003
4093
|
tempDir,
|
|
4004
4094
|
parentComponent,
|
|
4005
4095
|
);
|
|
4006
|
-
if (
|
|
4007
|
-
pkgList = pkgList.concat(
|
|
4096
|
+
if (rpkgMap.pkgList?.length) {
|
|
4097
|
+
pkgList = pkgList.concat(rpkgMap.pkgList);
|
|
4008
4098
|
pkgList = trimComponents(pkgList);
|
|
4009
4099
|
}
|
|
4010
|
-
if (
|
|
4011
|
-
formulationList = formulationList.concat(
|
|
4100
|
+
if (rpkgMap.formulationList?.length) {
|
|
4101
|
+
formulationList = formulationList.concat(rpkgMap.formulationList);
|
|
4012
4102
|
formulationList = trimComponents(formulationList);
|
|
4013
4103
|
}
|
|
4014
|
-
if (
|
|
4104
|
+
if (rpkgMap.dependenciesList) {
|
|
4015
4105
|
dependencies = mergeDependencies(
|
|
4016
4106
|
dependencies,
|
|
4017
|
-
|
|
4107
|
+
rpkgMap.dependenciesList,
|
|
4018
4108
|
parentComponent,
|
|
4019
4109
|
);
|
|
4020
4110
|
}
|
|
4021
4111
|
// Add the root packages from this file to the parent's dependencies
|
|
4022
|
-
for (const p of
|
|
4112
|
+
for (const p of rpkgMap.rootList) {
|
|
4023
4113
|
if (
|
|
4024
4114
|
parentComponent &&
|
|
4025
4115
|
p.name === parentComponent.name &&
|
|
@@ -4042,12 +4132,42 @@ export async function createPythonBom(path, options) {
|
|
|
4042
4132
|
parentComponent,
|
|
4043
4133
|
);
|
|
4044
4134
|
}
|
|
4045
|
-
|
|
4135
|
+
if (pkgMap) {
|
|
4136
|
+
// Complete the dependency tree by making parent component depend on the first level
|
|
4137
|
+
for (const p of pkgMap.rootList) {
|
|
4138
|
+
if (
|
|
4139
|
+
parentComponent &&
|
|
4140
|
+
p.name === parentComponent.name &&
|
|
4141
|
+
(p.version === parentComponent.version || p.version === "latest")
|
|
4142
|
+
) {
|
|
4143
|
+
continue;
|
|
4144
|
+
}
|
|
4145
|
+
parentDependsOn.add(`pkg:pypi/${p.name.toLowerCase()}@${p.version}`);
|
|
4146
|
+
}
|
|
4147
|
+
if (pkgMap?.pkgList?.length) {
|
|
4148
|
+
pkgList = pkgList.concat(pkgMap.pkgList);
|
|
4149
|
+
}
|
|
4150
|
+
if (pkgMap?.formulationList?.length) {
|
|
4151
|
+
formulationList = formulationList.concat(pkgMap.formulationList);
|
|
4152
|
+
}
|
|
4153
|
+
if (pkgMap?.dependenciesList) {
|
|
4154
|
+
dependencies = mergeDependencies(
|
|
4155
|
+
dependencies,
|
|
4156
|
+
pkgMap.dependenciesList,
|
|
4157
|
+
parentComponent,
|
|
4158
|
+
);
|
|
4159
|
+
}
|
|
4160
|
+
}
|
|
4046
4161
|
// ATOM parsedeps block
|
|
4047
4162
|
// Atom parsedeps slices can be used to identify packages that are not declared in manifests
|
|
4048
4163
|
// Since it is a slow operation, we only use it as a fallback or in deep mode
|
|
4049
4164
|
// This change was made in 10.9.2 release onwards
|
|
4050
4165
|
if (options.deep || !pkgList.length) {
|
|
4166
|
+
if (!pkgList.length) {
|
|
4167
|
+
thoughtLog(
|
|
4168
|
+
"I couldn't find any components yet. Let's try static analysis with atom parsedeps command.",
|
|
4169
|
+
);
|
|
4170
|
+
}
|
|
4051
4171
|
const retMap = await getPyModules(path, pkgList, options);
|
|
4052
4172
|
// We need to patch the existing package list to add ImportedModules for evinse to work
|
|
4053
4173
|
if (retMap.modList?.length) {
|
|
@@ -4096,32 +4216,6 @@ export async function createPythonBom(path, options) {
|
|
|
4096
4216
|
}
|
|
4097
4217
|
}
|
|
4098
4218
|
// ATOM parsedeps block
|
|
4099
|
-
if (pkgMap) {
|
|
4100
|
-
// Complete the dependency tree by making parent component depend on the first level
|
|
4101
|
-
for (const p of pkgMap.rootList) {
|
|
4102
|
-
if (
|
|
4103
|
-
parentComponent &&
|
|
4104
|
-
p.name === parentComponent.name &&
|
|
4105
|
-
(p.version === parentComponent.version || p.version === "latest")
|
|
4106
|
-
) {
|
|
4107
|
-
continue;
|
|
4108
|
-
}
|
|
4109
|
-
parentDependsOn.add(`pkg:pypi/${p.name.toLowerCase()}@${p.version}`);
|
|
4110
|
-
}
|
|
4111
|
-
if (pkgMap?.pkgList?.length) {
|
|
4112
|
-
pkgList = pkgList.concat(pkgMap.pkgList);
|
|
4113
|
-
}
|
|
4114
|
-
if (pkgMap?.formulationList?.length) {
|
|
4115
|
-
formulationList = formulationList.concat(pkgMap.formulationList);
|
|
4116
|
-
}
|
|
4117
|
-
if (pkgMap?.dependenciesList) {
|
|
4118
|
-
dependencies = mergeDependencies(
|
|
4119
|
-
dependencies,
|
|
4120
|
-
pkgMap.dependenciesList,
|
|
4121
|
-
parentComponent,
|
|
4122
|
-
);
|
|
4123
|
-
}
|
|
4124
|
-
}
|
|
4125
4219
|
let parentPresent = false;
|
|
4126
4220
|
for (const d of dependencies) {
|
|
4127
4221
|
if (d.ref === parentComponent["bom-ref"]) {
|
|
@@ -4140,7 +4234,6 @@ export async function createPythonBom(path, options) {
|
|
|
4140
4234
|
}
|
|
4141
4235
|
}
|
|
4142
4236
|
}
|
|
4143
|
-
|
|
4144
4237
|
// Final fallback is to manually parse setup.py if we still
|
|
4145
4238
|
// have an empty list
|
|
4146
4239
|
if (!pkgList.length && setupPyMode) {
|
package/lib/evinser/evinser.js
CHANGED
|
@@ -407,7 +407,7 @@ export function initFromSbom(components, language) {
|
|
|
407
407
|
const purlLocationMap = {};
|
|
408
408
|
const purlImportsMap = {};
|
|
409
409
|
for (const comp of components) {
|
|
410
|
-
if (!comp
|
|
410
|
+
if (!comp?.evidence) {
|
|
411
411
|
continue;
|
|
412
412
|
}
|
|
413
413
|
if (["php", "ruby"].includes(language)) {
|
|
@@ -648,8 +648,7 @@ export async function parseObjectSlices(
|
|
|
648
648
|
]) {
|
|
649
649
|
// Skip the library code typically without filename
|
|
650
650
|
if (
|
|
651
|
-
!slice.fileName ||
|
|
652
|
-
!slice.fileName.trim().length ||
|
|
651
|
+
!slice.fileName?.trim().length ||
|
|
653
652
|
slice.fileName === "<empty>" ||
|
|
654
653
|
slice.fileName === "<unknown>"
|
|
655
654
|
) {
|
|
@@ -1807,7 +1806,7 @@ export function collectReachableFrames(_language, reachablesSlice) {
|
|
|
1807
1806
|
* @returns
|
|
1808
1807
|
*/
|
|
1809
1808
|
export function framePicker(dfFrames) {
|
|
1810
|
-
if (!dfFrames
|
|
1809
|
+
if (!dfFrames?.length) {
|
|
1811
1810
|
return undefined;
|
|
1812
1811
|
}
|
|
1813
1812
|
let aframe = dfFrames[0];
|
package/lib/evinser/swiftsem.js
CHANGED
|
@@ -530,7 +530,7 @@ export function moduleInfo(moduleName, compilerArgs) {
|
|
|
530
530
|
* @returns {Object|undefined} Parsed classes, protocols, enums and their functions
|
|
531
531
|
*/
|
|
532
532
|
export function parseModuleInfo(moduleInfoJson) {
|
|
533
|
-
if (!moduleInfoJson
|
|
533
|
+
if (!moduleInfoJson?.["key.annotations"]) {
|
|
534
534
|
return undefined;
|
|
535
535
|
}
|
|
536
536
|
const classes = new Set();
|
package/lib/helpers/caxa.js
CHANGED
package/lib/helpers/display.js
CHANGED
|
@@ -24,7 +24,7 @@ export function printTable(
|
|
|
24
24
|
filterTypes = undefined,
|
|
25
25
|
highlight = undefined,
|
|
26
26
|
) {
|
|
27
|
-
if (!bomJson
|
|
27
|
+
if (!bomJson?.components) {
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
30
|
if (
|
|
@@ -120,7 +120,7 @@ export function printOSTable(bomJson) {
|
|
|
120
120
|
}
|
|
121
121
|
export function printServices(bomJson) {
|
|
122
122
|
const data = [["Name", "Endpoints", "Authenticated", "X Trust Boundary"]];
|
|
123
|
-
if (!bomJson
|
|
123
|
+
if (!bomJson?.services) {
|
|
124
124
|
return;
|
|
125
125
|
}
|
|
126
126
|
for (const aservice of bomJson.services) {
|
|
@@ -144,7 +144,7 @@ export function printServices(bomJson) {
|
|
|
144
144
|
|
|
145
145
|
export function printFormulation(bomJson) {
|
|
146
146
|
const data = [["Tyoe", "Name", "Version"]];
|
|
147
|
-
if (!bomJson
|
|
147
|
+
if (!bomJson?.formulation) {
|
|
148
148
|
return;
|
|
149
149
|
}
|
|
150
150
|
for (const aform of bomJson.formulation) {
|
|
@@ -179,7 +179,7 @@ const locationComparator = (a, b) => {
|
|
|
179
179
|
};
|
|
180
180
|
|
|
181
181
|
export function printOccurrences(bomJson) {
|
|
182
|
-
if (!bomJson
|
|
182
|
+
if (!bomJson?.components) {
|
|
183
183
|
return;
|
|
184
184
|
}
|
|
185
185
|
const data = ["Group", "Name", "Version", "Occurrences"];
|
|
@@ -219,15 +219,11 @@ export function printOccurrences(bomJson) {
|
|
|
219
219
|
|
|
220
220
|
export function printCallStack(bomJson) {
|
|
221
221
|
const data = [["Group", "Name", "Version", "Call Stack"]];
|
|
222
|
-
if (!bomJson
|
|
222
|
+
if (!bomJson?.components) {
|
|
223
223
|
return;
|
|
224
224
|
}
|
|
225
225
|
for (const comp of bomJson.components) {
|
|
226
|
-
if (
|
|
227
|
-
!comp.evidence ||
|
|
228
|
-
!comp.evidence.callstack ||
|
|
229
|
-
!comp.evidence.callstack.frames
|
|
230
|
-
) {
|
|
226
|
+
if (!comp.evidence?.callstack?.frames) {
|
|
231
227
|
continue;
|
|
232
228
|
}
|
|
233
229
|
const frames = Array.from(
|
|
@@ -30,13 +30,13 @@ export const GIT_COMMAND = process.env.GIT_CMD || "git";
|
|
|
30
30
|
// sdkman tool aliases
|
|
31
31
|
export const SDKMAN_JAVA_TOOL_ALIASES = {
|
|
32
32
|
java8: process.env.JAVA8_TOOL || "8.0.452-amzn", // Temurin no longer offers java8 :(
|
|
33
|
-
java11: process.env.JAVA11_TOOL || "11.0.
|
|
34
|
-
java17: process.env.JAVA17_TOOL || "17.0.
|
|
35
|
-
java21: process.env.JAVA21_TOOL || "21.0.
|
|
33
|
+
java11: process.env.JAVA11_TOOL || "11.0.30-tem",
|
|
34
|
+
java17: process.env.JAVA17_TOOL || "17.0.18-tem",
|
|
35
|
+
java21: process.env.JAVA21_TOOL || "21.0.10-tem",
|
|
36
36
|
java22: process.env.JAVA22_TOOL || "22.0.2-tem",
|
|
37
37
|
java23: process.env.JAVA23_TOOL || "23.0.2-tem",
|
|
38
38
|
java24: process.env.JAVA24_TOOL || "24.0.2-tem",
|
|
39
|
-
java25: process.env.JAVA25_TOOL || "25.0.
|
|
39
|
+
java25: process.env.JAVA25_TOOL || "25.0.2-tem",
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
/**
|
|
@@ -206,7 +206,7 @@ export function collectPythonInfo(dir) {
|
|
|
206
206
|
]);
|
|
207
207
|
const moduleDesc =
|
|
208
208
|
getCommandOutput(getPythonCommand(), dir, [
|
|
209
|
-
"-
|
|
209
|
+
"-I",
|
|
210
210
|
"-m",
|
|
211
211
|
"pip",
|
|
212
212
|
"--version",
|