@cyclonedx/cdxgen 11.1.5 → 11.1.7

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/bin/cdxgen.js CHANGED
@@ -28,6 +28,7 @@ import {
28
28
  isMac,
29
29
  isSecureMode,
30
30
  isWin,
31
+ safeExistsSync,
31
32
  } from "../lib/helpers/utils.js";
32
33
  import { validateBom } from "../lib/helpers/validator.js";
33
34
  import { postProcess } from "../lib/stages/postgen/postgen.js";
@@ -579,7 +580,9 @@ const checkPermissions = (filePath, options) => {
579
580
  console.log(
580
581
  "\x1b[1;35mSecure mode requires permission-related arguments. These can be passed as CLI arguments directly to the node runtime or set the NODE_OPTIONS environment variable as shown below.\x1b[0m",
581
582
  );
582
- const nodeOptionsVal = `--permission --allow-fs-read="${getTmpDir()}/*" --allow-fs-write="${getTmpDir()}/*" --allow-fs-read="${fullFilePath}/*" --allow-fs-write="${options.output}" --allow-child-process`;
583
+ const childProcessArgs =
584
+ options?.lifecycle !== "pre-build" ? " --allow-child-process" : "";
585
+ const nodeOptionsVal = `--permission --allow-fs-read="${getTmpDir()}/*" --allow-fs-write="${getTmpDir()}/*" --allow-fs-read="${fullFilePath}/*" --allow-fs-write="${options.output}"${childProcessArgs}`;
583
586
  console.log(
584
587
  `${isWin ? "$env:" : "export "}NODE_OPTIONS='${nodeOptionsVal}'`,
585
588
  );
@@ -680,11 +683,11 @@ const checkPermissions = (filePath, options) => {
680
683
  }
681
684
  if (!process.permission.has("fs.write", getTmpDir())) {
682
685
  console.log(
683
- `FileSystemWrite permission may be required to the TEMP directory. Please invoke cdxgen with the argument --allow-fs-write="${join(getTmpDir(), "*")}"`,
686
+ `FileSystemWrite permission may be required for the TEMP directory. Please invoke cdxgen with the argument --allow-fs-write="${join(getTmpDir(), "*")}" in case of any crashes.`,
684
687
  );
685
688
  if (isMac) {
686
689
  console.log(
687
- "TIP: macOS doesn't use `/tmp` prefix for TEMP directories. Use the argument shown above.",
690
+ "TIP: macOS doesn't use the `/tmp` prefix for TEMP directories. Use the argument shown above.",
688
691
  );
689
692
  }
690
693
  }
@@ -752,7 +755,7 @@ const checkPermissions = (filePath, options) => {
752
755
  (process.env.SBOM_SIGN_ALGORITHM &&
753
756
  process.env.SBOM_SIGN_ALGORITHM !== "none" &&
754
757
  process.env.SBOM_SIGN_PRIVATE_KEY &&
755
- fs.existsSync(process.env.SBOM_SIGN_PRIVATE_KEY)))
758
+ safeExistsSync(process.env.SBOM_SIGN_PRIVATE_KEY)))
756
759
  ) {
757
760
  let alg = process.env.SBOM_SIGN_ALGORITHM || "RS512";
758
761
  if (alg.includes("none")) {
@@ -794,7 +797,7 @@ const checkPermissions = (filePath, options) => {
794
797
  );
795
798
  if (
796
799
  process.env.SBOM_SIGN_PUBLIC_KEY &&
797
- fs.existsSync(process.env.SBOM_SIGN_PUBLIC_KEY)
800
+ safeExistsSync(process.env.SBOM_SIGN_PUBLIC_KEY)
798
801
  ) {
799
802
  jwkPublicKey = crypto
800
803
  .createPublicKey(
package/lib/cli/index.js CHANGED
@@ -3,9 +3,7 @@ import { spawnSync } from "node:child_process";
3
3
  import {
4
4
  constants,
5
5
  accessSync,
6
- existsSync,
7
6
  lstatSync,
8
- mkdirSync,
9
7
  mkdtempSync,
10
8
  readFileSync,
11
9
  rmSync,
@@ -152,6 +150,8 @@ import {
152
150
  parseYarnLock,
153
151
  readZipEntry,
154
152
  recomputeScope,
153
+ safeExistsSync,
154
+ safeMkdirSync,
155
155
  shouldFetchLicense,
156
156
  splitOutputByGradleProjects,
157
157
  } from "../helpers/utils.js";
@@ -242,7 +242,7 @@ const createDefaultParentComponent = (
242
242
  path = resolve(path);
243
243
  // Create a parent component based on the directory name
244
244
  let dirNameStr =
245
- existsSync(path) && lstatSync(path).isDirectory()
245
+ safeExistsSync(path) && lstatSync(path).isDirectory()
246
246
  ? basename(path)
247
247
  : dirname(path);
248
248
  const tmpA = dirNameStr.split(sep);
@@ -1274,7 +1274,7 @@ export function createBinaryBom(path, options) {
1274
1274
  const tempDir = mkdtempSync(join(getTmpDir(), "blint-tmp-"));
1275
1275
  const binaryBomFile = join(tempDir, "bom.json");
1276
1276
  getBinaryBom(path, binaryBomFile, options.deep);
1277
- if (existsSync(binaryBomFile)) {
1277
+ if (safeExistsSync(binaryBomFile)) {
1278
1278
  const binaryBom = JSON.parse(
1279
1279
  readFileSync(binaryBomFile, { encoding: "utf-8" }),
1280
1280
  );
@@ -1307,7 +1307,7 @@ export async function createJavaBom(path, options) {
1307
1307
  // war/ear mode
1308
1308
  if (path.endsWith(".war") || path.endsWith(".jar")) {
1309
1309
  // Check if the file exists
1310
- if (existsSync(path)) {
1310
+ if (safeExistsSync(path)) {
1311
1311
  if (DEBUG_MODE) {
1312
1312
  console.log(`Retrieving packages from ${path}`);
1313
1313
  }
@@ -1416,7 +1416,7 @@ export async function createJavaBom(path, options) {
1416
1416
  continue;
1417
1417
  }
1418
1418
  const settingsXml = join(basePath, "settings.xml");
1419
- if (existsSync(settingsXml)) {
1419
+ if (safeExistsSync(settingsXml)) {
1420
1420
  console.log(
1421
1421
  `maven settings.xml found in ${basePath}. Please set the MVN_ARGS environment variable based on the full mvn build command used for this project.\nExample: MVN_ARGS='--settings ${settingsXml}'`,
1422
1422
  );
@@ -1481,7 +1481,7 @@ export async function createJavaBom(path, options) {
1481
1481
  mvnTreeArgs = mvnTreeArgs.concat(addArgs);
1482
1482
  }
1483
1483
  // Automatically use settings.xml to improve the success for fallback
1484
- if (existsSync(settingsXml)) {
1484
+ if (safeExistsSync(settingsXml)) {
1485
1485
  mvnTreeArgs.push("-s");
1486
1486
  mvnTreeArgs.push(settingsXml);
1487
1487
  }
@@ -1500,7 +1500,7 @@ export async function createJavaBom(path, options) {
1500
1500
  },
1501
1501
  );
1502
1502
  if (result.status === 0) {
1503
- if (existsSync(tempMvnParentTree)) {
1503
+ if (safeExistsSync(tempMvnParentTree)) {
1504
1504
  const mvnTreeString = readFileSync(tempMvnParentTree, {
1505
1505
  encoding: "utf-8",
1506
1506
  });
@@ -1582,7 +1582,7 @@ export async function createJavaBom(path, options) {
1582
1582
  pkgList = pkgList.concat(dlist);
1583
1583
  }
1584
1584
  } else {
1585
- if (existsSync(tempMvnTree)) {
1585
+ if (safeExistsSync(tempMvnTree)) {
1586
1586
  const mvnTreeString = readFileSync(tempMvnTree, {
1587
1587
  encoding: "utf-8",
1588
1588
  });
@@ -1715,10 +1715,10 @@ export async function createJavaBom(path, options) {
1715
1715
  let gradleRootPath = path;
1716
1716
  if (
1717
1717
  gradleFiles?.length &&
1718
- !existsSync(join(path, "settings.gradle")) &&
1719
- !existsSync(join(path, "settings.gradle.kts")) &&
1720
- !existsSync(join(path, "build.gradle")) &&
1721
- !existsSync(join(path, "build.gradle.kts"))
1718
+ !safeExistsSync(join(path, "settings.gradle")) &&
1719
+ !safeExistsSync(join(path, "settings.gradle.kts")) &&
1720
+ !safeExistsSync(join(path, "build.gradle")) &&
1721
+ !safeExistsSync(join(path, "build.gradle.kts"))
1722
1722
  ) {
1723
1723
  gradleRootPath = dirname(gradleFiles[0]);
1724
1724
  }
@@ -1964,7 +1964,10 @@ export async function createJavaBom(path, options) {
1964
1964
  bazelTarget,
1965
1965
  ];
1966
1966
  // Automatically load any bazelrc file
1967
- if (!process.env.BAZEL_ARGS && existsSync(join(basePath, ".bazelrc"))) {
1967
+ if (
1968
+ !process.env.BAZEL_ARGS &&
1969
+ safeExistsSync(join(basePath, ".bazelrc"))
1970
+ ) {
1968
1971
  bArgs = ["--bazelrc=.bazelrc", "build", bazelTarget];
1969
1972
  }
1970
1973
  console.log("Executing", BAZEL_CMD, bArgs.join(" "), "in", basePath);
@@ -1988,7 +1991,10 @@ export async function createJavaBom(path, options) {
1988
1991
  let query = [...(process.env?.BAZEL_ARGS?.split(" ") || [])];
1989
1992
  let bazelParser;
1990
1993
  // Automatically load any bazelrc file
1991
- if (!process.env.BAZEL_ARGS && existsSync(join(basePath, ".bazelrc"))) {
1994
+ if (
1995
+ !process.env.BAZEL_ARGS &&
1996
+ safeExistsSync(join(basePath, ".bazelrc"))
1997
+ ) {
1992
1998
  query = ["--bazelrc=.bazelrc"];
1993
1999
  }
1994
2000
  if (["true", "1"].includes(process.env.BAZEL_USE_ACTION_GRAPH)) {
@@ -2121,7 +2127,7 @@ export async function createJavaBom(path, options) {
2121
2127
  sbtVersion != null && gte(sbtVersion, "1.4.0");
2122
2128
  const tempDir = mkdtempSync(join(getTmpDir(), "cdxsbt-"));
2123
2129
  const tempSbtgDir = mkdtempSync(join(getTmpDir(), "cdxsbtg-"));
2124
- mkdirSync(tempSbtgDir, { recursive: true });
2130
+ safeMkdirSync(tempSbtgDir, { recursive: true });
2125
2131
  // Create temporary plugins file
2126
2132
  const tempSbtPlugins = join(tempSbtgDir, "dep-plugins.sbt");
2127
2133
 
@@ -2191,7 +2197,7 @@ export async function createJavaBom(path, options) {
2191
2197
  if (!standalonePluginFile) {
2192
2198
  cleanupPlugin(basePath, pluginFile);
2193
2199
  }
2194
- if (existsSync(dlFile)) {
2200
+ if (safeExistsSync(dlFile)) {
2195
2201
  const retMap = parseSbtTree(dlFile);
2196
2202
  if (retMap.pkgList?.length) {
2197
2203
  const tmpParentComponent = retMap.pkgList.splice(0, 1)[0];
@@ -2410,7 +2416,7 @@ export async function createNodejsBom(path, options) {
2410
2416
  // Projects such as juice-shop prevent lockfile creations using .npmrc files
2411
2417
  // Plus, they might require specific npm install args such as --legacy-peer-deps that could lead to strange node_modules structure
2412
2418
  // To keep life simple, let's look for any .npmrc file that has package-lock=false to toggle before npm install
2413
- if (pkgMgr === "npm" && existsSync(join(basePath, ".npmrc"))) {
2419
+ if (pkgMgr === "npm" && safeExistsSync(join(basePath, ".npmrc"))) {
2414
2420
  const npmrcData = readFileSync(join(basePath, ".npmrc"));
2415
2421
  if (
2416
2422
  npmrcData?.includes("package-lock=false") &&
@@ -2606,7 +2612,7 @@ export async function createNodejsBom(path, options) {
2606
2612
  // Determine the parent component
2607
2613
  const packageJsonF = join(basePath, "package.json");
2608
2614
  if (!Object.keys(parentComponent).length) {
2609
- if (existsSync(packageJsonF)) {
2615
+ if (safeExistsSync(packageJsonF)) {
2610
2616
  const pcs = await parsePkgJson(packageJsonF, true);
2611
2617
  if (pcs.length && Object.keys(pcs[0]).length) {
2612
2618
  parentComponent = { ...pcs[0] };
@@ -2687,7 +2693,7 @@ export async function createNodejsBom(path, options) {
2687
2693
  if (!Object.keys(parentComponent).length) {
2688
2694
  const basePath = dirname(f);
2689
2695
  const packageJsonF = join(basePath, "package.json");
2690
- if (existsSync(packageJsonF)) {
2696
+ if (safeExistsSync(packageJsonF)) {
2691
2697
  const pcs = await parsePkgJson(packageJsonF, true);
2692
2698
  if (pcs.length && Object.keys(pcs[0]).length) {
2693
2699
  tmpParentComponent = { ...pcs[0] };
@@ -2727,13 +2733,13 @@ export async function createNodejsBom(path, options) {
2727
2733
  }
2728
2734
  }
2729
2735
  if (
2730
- existsSync(join(path, "rush.json")) &&
2736
+ safeExistsSync(join(path, "rush.json")) &&
2731
2737
  isPackageManagerAllowed("rush", ["npm", "yarn", "pnpm"], options)
2732
2738
  ) {
2733
2739
  // Rush.js creates node_modules inside common/temp directory
2734
2740
  const nmDir = join(path, "common", "temp", "node_modules");
2735
2741
  // Do rush install if we don't have node_modules directory
2736
- if (!existsSync(nmDir)) {
2742
+ if (!safeExistsSync(nmDir)) {
2737
2743
  console.log("Executing 'rush install --no-link'", path);
2738
2744
  const result = spawnSync(
2739
2745
  "rush",
@@ -2758,7 +2764,7 @@ export async function createNodejsBom(path, options) {
2758
2764
  "shrinkwrap-deps.json",
2759
2765
  );
2760
2766
  const pnpmLock = join(path, "common", "config", "rush", "pnpm-lock.yaml");
2761
- if (existsSync(swFile)) {
2767
+ if (safeExistsSync(swFile)) {
2762
2768
  let pkgList = await parseNodeShrinkwrap(swFile);
2763
2769
  if (allImports && Object.keys(allImports).length) {
2764
2770
  pkgList = await addEvidenceForImports(
@@ -2774,7 +2780,7 @@ export async function createNodejsBom(path, options) {
2774
2780
  filename: "shrinkwrap-deps.json",
2775
2781
  });
2776
2782
  }
2777
- if (existsSync(pnpmLock)) {
2783
+ if (safeExistsSync(pnpmLock)) {
2778
2784
  let pkgList = await parsePnpmLock(pnpmLock);
2779
2785
  if (allImports && Object.keys(allImports).length) {
2780
2786
  pkgList = await addEvidenceForImports(
@@ -2812,7 +2818,7 @@ export async function createNodejsBom(path, options) {
2812
2818
  const basePath = dirname(f);
2813
2819
  // Determine the parent component
2814
2820
  const packageJsonF = join(basePath, "package.json");
2815
- if (existsSync(packageJsonF)) {
2821
+ if (safeExistsSync(packageJsonF)) {
2816
2822
  const pcs = await parsePkgJson(packageJsonF, true);
2817
2823
  if (pcs.length && Object.keys(pcs[0]).length) {
2818
2824
  const tmpParentComponent = { ...pcs[0] };
@@ -2899,7 +2905,7 @@ export async function createNodejsBom(path, options) {
2899
2905
  }
2900
2906
  // We might reach here if the project has no lock files
2901
2907
  // Eg: juice-shop
2902
- if (!pkgList.length && existsSync(join(path, "node_modules"))) {
2908
+ if (!pkgList.length && safeExistsSync(join(path, "node_modules"))) {
2903
2909
  // Collect all package.json files from all node_modules directory
2904
2910
  const pkgJsonFiles = getAllFiles(
2905
2911
  path,
@@ -2914,7 +2920,7 @@ export async function createNodejsBom(path, options) {
2914
2920
  }
2915
2921
  }
2916
2922
  if (!parentComponent || !Object.keys(parentComponent).length) {
2917
- if (existsSync(join(path, "package.json"))) {
2923
+ if (safeExistsSync(join(path, "package.json"))) {
2918
2924
  const pcs = await parsePkgJson(join(path, "package.json"), true);
2919
2925
  if (pcs.length && Object.keys(pcs[0]).length) {
2920
2926
  parentComponent = { ...pcs[0] };
@@ -2982,7 +2988,7 @@ export function createPixiBom(path, options) {
2982
2988
 
2983
2989
  // if pixi.toml file found then we
2984
2990
  // Add parentComponent Details
2985
- const pixiTomlMode = existsSync(pixiToml);
2991
+ const pixiTomlMode = safeExistsSync(pixiToml);
2986
2992
  if (pixiTomlMode) {
2987
2993
  parentComponent = parsePixiTomlFile(pixiToml);
2988
2994
  parentComponent.type = "application";
@@ -2999,7 +3005,7 @@ export function createPixiBom(path, options) {
2999
3005
  }
3000
3006
 
3001
3007
  const pixiLockFile = join(path, "pixi.lock");
3002
- const pixiFilesMode = existsSync(pixiLockFile);
3008
+ const pixiFilesMode = safeExistsSync(pixiLockFile);
3003
3009
  if (pixiFilesMode) {
3004
3010
  // Instead of what we do in createPythonBOM
3005
3011
  // where we install packages and run `getPipFrozenTree`
@@ -3012,7 +3018,7 @@ export function createPixiBom(path, options) {
3012
3018
  generatePixiLockFile(path);
3013
3019
 
3014
3020
  const pixiLockFile = join(path, "pixi.lock");
3015
- if (!existsSync(pixiLockFile) && DEBUG_MODE) {
3021
+ if (!safeExistsSync(pixiLockFile) && DEBUG_MODE) {
3016
3022
  console.log(
3017
3023
  "Unexpected Error tried to generate pixi.lock file but failed.",
3018
3024
  );
@@ -3056,13 +3062,13 @@ export async function createPythonBom(path, options) {
3056
3062
  const tempDir = mkdtempSync(join(getTmpDir(), "cdxgen-venv-"));
3057
3063
  let parentComponent = createDefaultParentComponent(path, "pypi", options);
3058
3064
  // We are checking only the root here for pipenv
3059
- const pipenvMode = existsSync(join(path, "Pipfile"));
3065
+ const pipenvMode = safeExistsSync(join(path, "Pipfile"));
3060
3066
 
3061
3067
  // If pixi is used then just return that as output instead
3062
3068
  const pixiLockFile = join(path, "pixi.lock");
3063
- const pixiFilesMode = existsSync(pixiLockFile);
3069
+ const pixiFilesMode = safeExistsSync(pixiLockFile);
3064
3070
  const pixiToml = join(path, "pixi.toml");
3065
- const pixiTomlMode = existsSync(pixiToml);
3071
+ const pixiTomlMode = safeExistsSync(pixiToml);
3066
3072
  if (pixiTomlMode || pixiFilesMode) {
3067
3073
  const BomNSData = createPixiBom(path, options);
3068
3074
  if (BomNSData) {
@@ -3123,7 +3129,7 @@ export async function createPythonBom(path, options) {
3123
3129
  // Is this a pyproject based project.
3124
3130
  // TODO: Support nested directories
3125
3131
  const pyProjectFile = join(path, "pyproject.toml");
3126
- const pyProjectMode = existsSync(pyProjectFile);
3132
+ const pyProjectMode = safeExistsSync(pyProjectFile);
3127
3133
  if (pyProjectMode) {
3128
3134
  const pyProjMap = parsePyProjectTomlFile(pyProjectFile);
3129
3135
  const tmpParentComponent = pyProjMap.parentComponent;
@@ -3156,7 +3162,7 @@ export async function createPythonBom(path, options) {
3156
3162
 
3157
3163
  // TODO: Support for nested directories
3158
3164
  const setupPy = join(path, "setup.py");
3159
- const setupPyMode = existsSync(setupPy);
3165
+ const setupPyMode = safeExistsSync(setupPy);
3160
3166
  // Poetry sets up its own virtual env containing site-packages so
3161
3167
  // we give preference to poetry lock file. Issue# 129
3162
3168
  if (poetryMode) {
@@ -3262,7 +3268,7 @@ export async function createPythonBom(path, options) {
3262
3268
  // TODO: Support for nested directories
3263
3269
  spawnSync("pipenv", ["install"], { cwd: path, encoding: "utf-8" });
3264
3270
  const piplockFile = join(path, "Pipfile.lock");
3265
- if (existsSync(piplockFile)) {
3271
+ if (safeExistsSync(piplockFile)) {
3266
3272
  const lockData = JSON.parse(readFileSync(piplockFile));
3267
3273
  const dlist = await parsePiplockData(lockData);
3268
3274
  if (dlist?.length) {
@@ -3967,7 +3973,7 @@ export async function createRustBom(path, options) {
3967
3973
  if (
3968
3974
  options.deep === true ||
3969
3975
  (options.installDeps &&
3970
- !existsSync(f.replace(".toml", ".lock")) &&
3976
+ !safeExistsSync(f.replace(".toml", ".lock")) &&
3971
3977
  ["build", "post-build"].includes(options.lifecycle))
3972
3978
  ) {
3973
3979
  const basePath = dirname(f);
@@ -5213,7 +5219,7 @@ export function createPHPBom(path, options) {
5213
5219
  );
5214
5220
  if (composerLockFiles.length) {
5215
5221
  // Look for any root composer.json to capture the parentComponent
5216
- if (existsSync(join(path, "composer.json"))) {
5222
+ if (safeExistsSync(join(path, "composer.json"))) {
5217
5223
  const { moduleParent } = parseComposerJson(join(path, "composer.json"));
5218
5224
  parentComponent = moduleParent;
5219
5225
  }
@@ -5225,7 +5231,7 @@ export function createPHPBom(path, options) {
5225
5231
  }
5226
5232
  let rootRequires = [];
5227
5233
  // Is there a composer.json to find the module parent component
5228
- if (existsSync(join(basePath, "composer.json"))) {
5234
+ if (safeExistsSync(join(basePath, "composer.json"))) {
5229
5235
  const retMap = parseComposerJson(join(basePath, "composer.json"));
5230
5236
  moduleParent = retMap.moduleParent;
5231
5237
  rootRequires = retMap.rootRequires;
@@ -5884,7 +5890,7 @@ export async function createCsharpBom(path, options) {
5884
5890
  join(path, options.depsSlicesFile) || join(getTmpDir(), "dosai.json"),
5885
5891
  );
5886
5892
  // Create the slices file if it doesn't exist
5887
- if (!existsSync(slicesFile)) {
5893
+ if (!safeExistsSync(slicesFile)) {
5888
5894
  const sliceResult = getDotnetSlices(resolve(path), resolve(slicesFile));
5889
5895
  if (!sliceResult && DEBUG_MODE) {
5890
5896
  console.log(
@@ -6745,9 +6751,9 @@ export async function createXBom(path, options) {
6745
6751
  return undefined;
6746
6752
  }
6747
6753
  if (
6748
- existsSync(join(path, "package.json")) ||
6749
- existsSync(join(path, "rush.json")) ||
6750
- existsSync(join(path, "yarn.lock"))
6754
+ safeExistsSync(join(path, "package.json")) ||
6755
+ safeExistsSync(join(path, "rush.json")) ||
6756
+ safeExistsSync(join(path, "yarn.lock"))
6751
6757
  ) {
6752
6758
  return await createNodejsBom(path, options);
6753
6759
  }
@@ -6773,10 +6779,11 @@ export async function createXBom(path, options) {
6773
6779
  return await createJavaBom(path, options);
6774
6780
  }
6775
6781
  // python
6776
- const pipenvMode = existsSync(join(path, "Pipfile"));
6777
- const poetryMode = existsSync(join(path, "poetry.lock"));
6778
- const pyProjectMode = !poetryMode && existsSync(join(path, "pyproject.toml"));
6779
- const setupPyMode = existsSync(join(path, "setup.py"));
6782
+ const pipenvMode = safeExistsSync(join(path, "Pipfile"));
6783
+ const poetryMode = safeExistsSync(join(path, "poetry.lock"));
6784
+ const pyProjectMode =
6785
+ !poetryMode && safeExistsSync(join(path, "pyproject.toml"));
6786
+ const setupPyMode = safeExistsSync(join(path, "setup.py"));
6780
6787
  if (pipenvMode || poetryMode || pyProjectMode || setupPyMode) {
6781
6788
  return await createPythonBom(path, options);
6782
6789
  }
@@ -7111,7 +7118,7 @@ export async function createBom(path, options) {
7111
7118
  allLayersDir: path,
7112
7119
  allLayersExplodedDir: path,
7113
7120
  };
7114
- if (existsSync(join(path, "all-layers"))) {
7121
+ if (safeExistsSync(join(path, "all-layers"))) {
7115
7122
  exportData.allLayersDir = join(path, "all-layers");
7116
7123
  }
7117
7124
  exportData.pkgPathList = getPkgPathList(exportData, undefined);
@@ -16,6 +16,8 @@ import {
16
16
  getMavenCommand,
17
17
  getTimestamp,
18
18
  getTmpDir,
19
+ safeExistsSync,
20
+ safeMkdirSync,
19
21
  } from "../helpers/utils.js";
20
22
  import { postProcess } from "../stages/postgen/postgen.js";
21
23
  import { createSemanticsSlices } from "./swiftsem.js";
@@ -29,16 +31,16 @@ const typePurlsCache = {};
29
31
  * @param {Object} options Command line options
30
32
  */
31
33
  export async function prepareDB(options) {
32
- if (!options.dbPath.includes("memory") && !fs.existsSync(options.dbPath)) {
34
+ if (!options.dbPath.includes("memory") && !safeExistsSync(options.dbPath)) {
33
35
  try {
34
- fs.mkdirSync(options.dbPath, { recursive: true });
36
+ safeMkdirSync(options.dbPath, { recursive: true });
35
37
  } catch (e) {
36
38
  // ignore
37
39
  }
38
40
  }
39
41
  const dirPath = options._[0] || ".";
40
42
  const bomJsonFile = options.input;
41
- if (!fs.existsSync(bomJsonFile)) {
43
+ if (!safeExistsSync(bomJsonFile)) {
42
44
  console.log(
43
45
  "Bom file doesn't exist. Check if cdxgen was invoked with the correct type argument.",
44
46
  );
@@ -102,7 +104,7 @@ export async function catalogMavenDeps(
102
104
  options = {},
103
105
  ) {
104
106
  let jarNSMapping = undefined;
105
- if (fs.existsSync(path.join(dirPath, "bom.json.map"))) {
107
+ if (safeExistsSync(path.join(dirPath, "bom.json.map"))) {
106
108
  try {
107
109
  const mapData = JSON.parse(
108
110
  fs.readFileSync(path.join(dirPath, "bom.json.map"), "utf-8"),
@@ -190,7 +192,7 @@ export async function createAndStoreSlice(
190
192
  ) {
191
193
  const retMap = createSlice(purl, purlsJars[purl], "usages", options);
192
194
  let sliceData = undefined;
193
- if (retMap?.slicesFile && fs.existsSync(retMap.slicesFile)) {
195
+ if (retMap?.slicesFile && safeExistsSync(retMap.slicesFile)) {
194
196
  sliceData = await Usages.findOrCreate({
195
197
  where: { purl },
196
198
  defaults: {
@@ -245,7 +247,7 @@ export async function createSlice(
245
247
  );
246
248
  if (options?.output) {
247
249
  sliceOutputDir =
248
- fs.existsSync(options.output) &&
250
+ safeExistsSync(options.output) &&
249
251
  fs.lstatSync(options.output).isDirectory()
250
252
  ? path.basename(options.output)
251
253
  : path.dirname(options.output);
@@ -290,7 +292,7 @@ export async function createSlice(
290
292
 
291
293
  args.push(path.resolve(filePath));
292
294
  const result = executeAtom(filePath, args);
293
- if (!result || !fs.existsSync(slicesFile)) {
295
+ if (!result || !safeExistsSync(slicesFile)) {
294
296
  console.warn(
295
297
  `Unable to generate ${sliceType} slice using atom. Check if this is a supported language.`,
296
298
  );
@@ -378,7 +380,7 @@ export function initFromSbom(components, language) {
378
380
  }
379
381
 
380
382
  function usableSlicesFile(slicesFile) {
381
- if (!slicesFile || !fs.existsSync(slicesFile)) {
383
+ if (!slicesFile || !safeExistsSync(slicesFile)) {
382
384
  return false;
383
385
  }
384
386
  const stats = fs.statSync(slicesFile);
@@ -432,7 +434,7 @@ export async function analyzeProject(dbObjMap, options) {
432
434
  );
433
435
  } else {
434
436
  retMap = await createSlice(language, dirPath, "reachables", options);
435
- if (retMap?.slicesFile && fs.existsSync(retMap.slicesFile)) {
437
+ if (retMap?.slicesFile && safeExistsSync(retMap.slicesFile)) {
436
438
  reachablesSlicesFile = retMap.slicesFile;
437
439
  reachablesSlice = JSON.parse(
438
440
  fs.readFileSync(retMap.slicesFile, "utf-8"),
@@ -453,7 +455,7 @@ export async function analyzeProject(dbObjMap, options) {
453
455
  } else {
454
456
  // Generate our own slices
455
457
  retMap = await createSlice(language, dirPath, "usages", options);
456
- if (retMap?.slicesFile && fs.existsSync(retMap.slicesFile)) {
458
+ if (retMap?.slicesFile && safeExistsSync(retMap.slicesFile)) {
457
459
  usageSlice = JSON.parse(fs.readFileSync(retMap.slicesFile, "utf-8"));
458
460
  usagesSlicesFile = retMap.slicesFile;
459
461
  }
@@ -463,7 +465,7 @@ export async function analyzeProject(dbObjMap, options) {
463
465
  // Reuse existing semantics slices
464
466
  if (
465
467
  options.semanticsSlicesFile &&
466
- fs.existsSync(options.semanticsSlicesFile)
468
+ safeExistsSync(options.semanticsSlicesFile)
467
469
  ) {
468
470
  semanticsSlice = JSON.parse(
469
471
  fs.readFileSync(options.semanticsSlicesFile, "utf-8"),
@@ -472,7 +474,7 @@ export async function analyzeProject(dbObjMap, options) {
472
474
  } else {
473
475
  // Generate our own slices
474
476
  retMap = await createSlice(language, dirPath, "semantics", options);
475
- if (retMap?.slicesFile && fs.existsSync(retMap.slicesFile)) {
477
+ if (retMap?.slicesFile && safeExistsSync(retMap.slicesFile)) {
476
478
  semanticsSlice = JSON.parse(
477
479
  fs.readFileSync(retMap.slicesFile, "utf-8"),
478
480
  );
@@ -507,7 +509,7 @@ export async function analyzeProject(dbObjMap, options) {
507
509
  if (options.withDataFlow) {
508
510
  if (
509
511
  options.dataFlowSlicesFile &&
510
- fs.existsSync(options.dataFlowSlicesFile)
512
+ safeExistsSync(options.dataFlowSlicesFile)
511
513
  ) {
512
514
  dataFlowSlicesFile = options.dataFlowSlicesFile;
513
515
  dataFlowSlice = JSON.parse(
@@ -515,7 +517,7 @@ export async function analyzeProject(dbObjMap, options) {
515
517
  );
516
518
  } else {
517
519
  retMap = await createSlice(language, dirPath, "data-flow", options);
518
- if (retMap?.slicesFile && fs.existsSync(retMap.slicesFile)) {
520
+ if (retMap?.slicesFile && safeExistsSync(retMap.slicesFile)) {
519
521
  dataFlowSlicesFile = retMap.slicesFile;
520
522
  dataFlowSlice = JSON.parse(fs.readFileSync(retMap.slicesFile, "utf-8"));
521
523
  }
@@ -1359,7 +1361,7 @@ export function createEvinseFile(sliceArtefacts, options) {
1359
1361
  bomJson.dependencies = newDependencies;
1360
1362
  }
1361
1363
  if (options.annotate) {
1362
- if (usagesSlicesFile && fs.existsSync(usagesSlicesFile)) {
1364
+ if (usagesSlicesFile && safeExistsSync(usagesSlicesFile)) {
1363
1365
  bomJson.annotations.push({
1364
1366
  subjects: [bomJson.serialNumber],
1365
1367
  annotator: { component: bomJson.metadata.tools.components[0] },
@@ -1367,7 +1369,7 @@ export function createEvinseFile(sliceArtefacts, options) {
1367
1369
  text: fs.readFileSync(usagesSlicesFile, "utf8"),
1368
1370
  });
1369
1371
  }
1370
- if (dataFlowSlicesFile && fs.existsSync(dataFlowSlicesFile)) {
1372
+ if (dataFlowSlicesFile && safeExistsSync(dataFlowSlicesFile)) {
1371
1373
  bomJson.annotations.push({
1372
1374
  subjects: [bomJson.serialNumber],
1373
1375
  annotator: { component: bomJson.metadata.tools.components[0] },
@@ -1375,7 +1377,7 @@ export function createEvinseFile(sliceArtefacts, options) {
1375
1377
  text: fs.readFileSync(dataFlowSlicesFile, "utf8"),
1376
1378
  });
1377
1379
  }
1378
- if (reachablesSlicesFile && fs.existsSync(reachablesSlicesFile)) {
1380
+ if (reachablesSlicesFile && safeExistsSync(reachablesSlicesFile)) {
1379
1381
  bomJson.annotations.push({
1380
1382
  subjects: [bomJson.serialNumber],
1381
1383
  annotator: { component: bomJson.metadata.tools.components[0] },
@@ -1,6 +1,5 @@
1
1
  import { Buffer } from "node:buffer";
2
2
  import { spawnSync } from "node:child_process";
3
- import { existsSync } from "node:fs";
4
3
  import { arch, homedir } from "node:os";
5
4
  import { delimiter, dirname, join } from "node:path";
6
5
  import process from "node:process";
@@ -23,18 +22,19 @@ import {
23
22
  getTmpDir,
24
23
  isMac,
25
24
  isWin,
25
+ safeExistsSync,
26
26
  } from "./utils.js";
27
27
 
28
28
  export const GIT_COMMAND = process.env.GIT_CMD || "git";
29
29
 
30
30
  // sdkman tool aliases
31
31
  export const SDKMAN_JAVA_TOOL_ALIASES = {
32
- java8: process.env.JAVA8_TOOL || "8.0.432-tem",
32
+ java8: process.env.JAVA8_TOOL || "8.0.442-amzn", // Temurin no longer offers java8 :(
33
33
  java11: process.env.JAVA11_TOOL || "11.0.25-tem",
34
34
  java17: process.env.JAVA17_TOOL || "17.0.14-tem",
35
35
  java21: process.env.JAVA21_TOOL || "21.0.6-tem",
36
36
  java22: process.env.JAVA22_TOOL || "22.0.2-tem",
37
- java23: process.env.JAVA23_TOOL || "23.0.1-tem",
37
+ java23: process.env.JAVA23_TOOL || "23.0.2-tem",
38
38
  };
39
39
 
40
40
  /**
@@ -421,9 +421,9 @@ const getCommandOutput = (cmd, dir, args) => {
421
421
  export function isSdkmanAvailable() {
422
422
  let isSdkmanSetup =
423
423
  ["SDKMAN_DIR", "SDKMAN_CANDIDATES_DIR"].filter(
424
- (v) => process.env[v] && existsSync(process.env[v]),
424
+ (v) => process.env[v] && safeExistsSync(process.env[v]),
425
425
  ).length >= 1;
426
- if (!isSdkmanSetup && existsSync(join(homedir(), ".sdkman", "bin"))) {
426
+ if (!isSdkmanSetup && safeExistsSync(join(homedir(), ".sdkman", "bin"))) {
427
427
  process.env.SDKMAN_DIR = join(homedir(), ".sdkman");
428
428
  process.env.SDKMAN_CANDIDATES_DIR = join(
429
429
  homedir(),
@@ -462,12 +462,12 @@ export function isSdkmanToolAvailable(toolType, toolName) {
462
462
  toolName = getSdkmanToolFullname(toolName);
463
463
  let isToolAvailable =
464
464
  process.env.SDKMAN_CANDIDATES_DIR &&
465
- existsSync(
465
+ safeExistsSync(
466
466
  join(process.env.SDKMAN_CANDIDATES_DIR, toolType, toolName, "bin"),
467
467
  );
468
468
  if (
469
469
  !isToolAvailable &&
470
- existsSync(
470
+ safeExistsSync(
471
471
  join(homedir(), ".sdkman", "candidates", toolType, toolName, "bin"),
472
472
  )
473
473
  ) {
@@ -549,7 +549,7 @@ export function installSdkmanTool(toolType, toolName) {
549
549
  );
550
550
  } else if (
551
551
  process.env.SDKMAN_CANDIDATES_DIR &&
552
- existsSync(join(process.env.SDKMAN_CANDIDATES_DIR, toolType, toolName))
552
+ safeExistsSync(join(process.env.SDKMAN_CANDIDATES_DIR, toolType, toolName))
553
553
  ) {
554
554
  process.env[`${toolUpper}_HOME`] = join(
555
555
  process.env.SDKMAN_CANDIDATES_DIR,
@@ -740,7 +740,7 @@ export function bundleInstallWithDocker(rubyVersion, cdxgenGemHome, filePath) {
740
740
  if (result.error || result.status !== 0) {
741
741
  return false;
742
742
  }
743
- if (existsSync(join(filePath, "Gemfile.lock"))) {
743
+ if (safeExistsSync(join(filePath, "Gemfile.lock"))) {
744
744
  console.log(
745
745
  "Gemfile.lock was generated successfully. Thank you for trying this feature!",
746
746
  );
@@ -763,7 +763,7 @@ export function installRubyVersion(rubyVersion, filePath) {
763
763
  return { fullToolBinDir: undefined, status: true };
764
764
  }
765
765
  const fullToolBinDir = rubyVersionDir(rubyVersion);
766
- if (existsSync(fullToolBinDir)) {
766
+ if (safeExistsSync(fullToolBinDir)) {
767
767
  const result = spawnSync(
768
768
  process.env.RBENV_CMD || "rbenv",
769
769
  ["local", rubyVersion],
@@ -861,7 +861,7 @@ export function installRubyBundler(rubyVersion, bundlerVersion) {
861
861
  bundlerWarningShown = true;
862
862
  }
863
863
  const fullToolBinDir = rubyVersionDir(rubyVersion);
864
- if (existsSync(fullToolBinDir)) {
864
+ if (safeExistsSync(fullToolBinDir)) {
865
865
  const gemInstallArgs = ["install", "bundler"];
866
866
  if (bundlerVersion) {
867
867
  gemInstallArgs.push("-v");
@@ -1038,7 +1038,7 @@ export function performBundleInstall(
1038
1038
  "This project requires a specific version of RubyGems. To do this, the existing version must be uninstalled followed by installing the required version. `sudo gem uninstall rubygems-update -v <existing version>` and then `sudo gem install rubygems-update -v <required version>`.",
1039
1039
  );
1040
1040
  rubyVersionWarningShown = true;
1041
- if (existsSync(gemFileLock)) {
1041
+ if (safeExistsSync(gemFileLock)) {
1042
1042
  console.log("Run `bundle install` command to troubleshoot the build.");
1043
1043
  } else {
1044
1044
  console.log(
@@ -41,7 +41,7 @@ test("tools tests", () => {
41
41
  test("sdkman tests", () => {
42
42
  if (process.env?.SDKMAN_VERSION) {
43
43
  expect(isSdkmanAvailable()).toBeTruthy();
44
- expect(isSdkmanToolAvailable("java", "23.0.1-tem")).toBeTruthy();
44
+ expect(isSdkmanToolAvailable("java", "23.0.2-tem")).toBeTruthy();
45
45
  }
46
46
  });
47
47