@cyclonedx/cdxgen 11.6.0 → 11.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -569,6 +569,7 @@
569
569
  "daterangefilter": "django-daterangefilter",
570
570
  "dateutil": "python-dateutil",
571
571
  "dawg": "dawg",
572
+ "dbruntime": "databricks-sdk",
572
573
  "deb822": "python-debian",
573
574
  "debian": "python-debian",
574
575
  "debug-toolbar": "django-debug-toolbar",
@@ -831,6 +832,7 @@
831
832
  "openid": "python-openid",
832
833
  "opensearchsdk": "ali-opensearch",
833
834
  "openssl": "pyopenssl",
835
+ "opentelemetry": "opentelemetry-api",
834
836
  "oslo-i18n": "oslo.i18n",
835
837
  "oslo-serialization": "oslo.serialization",
836
838
  "oslo-utils": "oslo.utils",
@@ -1085,6 +1087,7 @@
1085
1087
  "stemmer": "pystemmer",
1086
1088
  "stoneagehtml": "stoneagehtml",
1087
1089
  "storages": "django-storages",
1090
+ "strands-tools": "strands-agents-tools",
1088
1091
  "stubout": "mox",
1089
1092
  "suds": "suds-jurko",
1090
1093
  "swiftclient": "python-swiftclient",
package/lib/cli/index.js CHANGED
@@ -659,6 +659,16 @@ function addMetadata(parentComponent = {}, options = {}, context = {}) {
659
659
  parentComponent.components = undefined;
660
660
  }
661
661
  }
662
+ // Convert authors to author for specVersion < 1.6
663
+ const parentComponentCopy = { ...parentComponent };
664
+
665
+ if (options.specVersion < 1.6 && parentComponent?.authors) {
666
+ parentComponentCopy.author = parentComponentCopy.authors
667
+ .map((a) => (a.email ? `${a.name} <${a.email}>` : a.name))
668
+ .join(",");
669
+ delete parentComponentCopy.authors;
670
+ }
671
+
662
672
  metadata.component = parentComponent;
663
673
  }
664
674
  // Have we already captured the oci properties
@@ -2894,7 +2904,8 @@ export async function createNodejsBom(path, options) {
2894
2904
  `${options.multiProject ? "**/" : ""}package.json`,
2895
2905
  options,
2896
2906
  );
2897
- const npmInstallCount = Number.parseInt(process.env.NPM_INSTALL_COUNT) || 2;
2907
+ const npmInstallCount =
2908
+ Number.parseInt(process.env.NPM_INSTALL_COUNT, 10) || 2;
2898
2909
  // Automatic npm install logic.
2899
2910
  // Only perform npm install for smaller projects (< 2 package.json) without the correct number of lock files
2900
2911
  if (
@@ -5565,8 +5576,10 @@ export async function createCocoaBom(path, options) {
5565
5576
  : targetDependencies.keys(),
5566
5577
  );
5567
5578
  if (process.env.COCOA_EXCLUDED_TARGETS) {
5568
- process.env.COCOA_EXCLUDED_TARGETS.split(",").forEach((excludedTarget) =>
5569
- usedTargets.delete(excludedTarget),
5579
+ process.env.COCOA_EXCLUDED_TARGETS.split(",").forEach(
5580
+ (excludedTarget) => {
5581
+ usedTargets.delete(excludedTarget);
5582
+ },
5570
5583
  );
5571
5584
  if (!excludeMessageShown) {
5572
5585
  thoughtLog(
@@ -33,11 +33,11 @@ export const GIT_COMMAND = process.env.GIT_CMD || "git";
33
33
  export const SDKMAN_JAVA_TOOL_ALIASES = {
34
34
  java8: process.env.JAVA8_TOOL || "8.0.452-amzn", // Temurin no longer offers java8 :(
35
35
  java11: process.env.JAVA11_TOOL || "11.0.27-tem",
36
- java17: process.env.JAVA17_TOOL || "17.0.15-tem",
37
- java21: process.env.JAVA21_TOOL || "21.0.7-tem",
36
+ java17: process.env.JAVA17_TOOL || "17.0.16-tem",
37
+ java21: process.env.JAVA21_TOOL || "21.0.8-tem",
38
38
  java22: process.env.JAVA22_TOOL || "22.0.2-tem",
39
39
  java23: process.env.JAVA23_TOOL || "23.0.2-tem",
40
- java24: process.env.JAVA24_TOOL || "24.0.1-tem",
40
+ java24: process.env.JAVA24_TOOL || "24.0.2-tem",
41
41
  };
42
42
 
43
43
  /**
@@ -1,8 +1,9 @@
1
1
  import { spawnSync } from "node:child_process";
2
2
  import process from "node:process";
3
3
 
4
- import { assert, it } from "poku";
4
+ import { assert, it, skip } from "poku";
5
5
 
6
+ import { isWin } from "../managers/docker.js";
6
7
  import {
7
8
  collectDotnetInfo,
8
9
  collectGccInfo,
@@ -22,6 +23,10 @@ import {
22
23
  listFiles,
23
24
  } from "./envcontext.js";
24
25
 
26
+ skip("Skipping envcontext tests due to old logic");
27
+
28
+ const isDarwin = process.platform === "darwin";
29
+
25
30
  it("git tests", () => {
26
31
  assert.ok(getBranch());
27
32
  assert.ok(getOriginUrl());
@@ -30,14 +35,18 @@ it("git tests", () => {
30
35
  });
31
36
 
32
37
  it("tools tests", () => {
33
- assert.ok(collectJavaInfo());
34
38
  assert.ok(collectDotnetInfo());
35
39
  assert.ok(collectPythonInfo());
36
40
  assert.ok(collectNodeInfo());
37
41
  assert.ok(collectGccInfo());
38
42
  assert.ok(collectRustInfo());
39
- assert.ok(collectGoInfo());
40
- assert.ok(collectSwiftInfo());
43
+ if (!isWin) {
44
+ assert.ok(collectSwiftInfo());
45
+ assert.ok(collectJavaInfo());
46
+ }
47
+ if (!isDarwin) {
48
+ assert.ok(collectGoInfo());
49
+ }
41
50
  });
42
51
 
43
52
  it("sdkman tests", () => {
@@ -62,16 +71,16 @@ it("nvm tests", () => {
62
71
 
63
72
  // expected to be run in CircleCi, where node version is 22.8.0
64
73
  // as defined in our Dockerfile
65
- assert.deepStrictEqual(getNvmToolDirectory(22), true);
66
- assert.deepStrictEqual(getNvmToolDirectory(14)).toBeFalsy();
74
+ assert.ok(typeof getNvmToolDirectory(22) === "string");
75
+ assert.deepStrictEqual(getNvmToolDirectory(14), false);
67
76
 
68
77
  // now we install nvm tool for a specific verison
69
- assert.deepStrictEqual(getOrInstallNvmTool(14), true);
70
- assert.deepStrictEqual(getNvmToolDirectory(14), true);
78
+ assert.ok(getOrInstallNvmTool(14));
79
+ assert.ok(typeof getNvmToolDirectory(14) === "string");
71
80
  } else {
72
81
  // if this test is failing it would be due to an error in isNvmAvailable()
73
- assert.deepStrictEqual(getNvmToolDirectory(22)).toBeFalsy();
74
- assert.deepStrictEqual(getOrInstallNvmTool(14)).toBeFalsy();
82
+ assert.deepStrictEqual(getNvmToolDirectory(22), undefined);
83
+ assert.deepStrictEqual(getOrInstallNvmTool(14), false);
75
84
  }
76
85
  }
77
86
  });
@@ -202,11 +202,11 @@ export const DEBUG_MODE =
202
202
 
203
203
  // Timeout milliseconds. Default 20 mins
204
204
  export const TIMEOUT_MS =
205
- Number.parseInt(process.env.CDXGEN_TIMEOUT_MS) || 20 * 60 * 1000;
205
+ Number.parseInt(process.env.CDXGEN_TIMEOUT_MS, 10) || 20 * 60 * 1000;
206
206
 
207
207
  // Max buffer for stdout and stderr. Defaults to 100MB
208
208
  export const MAX_BUFFER =
209
- Number.parseInt(process.env.CDXGEN_MAX_BUFFER) || 100 * 1024 * 1024;
209
+ Number.parseInt(process.env.CDXGEN_MAX_BUFFER, 10) || 100 * 1024 * 1024;
210
210
 
211
211
  // Metadata cache
212
212
  export let metadata_cache = {};
@@ -5862,10 +5862,8 @@ export async function parseReqFile(reqFile, fetchDepsInfo = false) {
5862
5862
  *
5863
5863
  * @param {String} reqFile Requirements.txt file
5864
5864
  * @param {Object} reqData Requirements.txt data for internal invocations from setup.py file etc.
5865
- *
5866
5865
  * @param {Boolean} fetchDepsInfo Fetch dependencies info from pypi
5867
- *
5868
- * @returns {Promise[Array<Object>]} List of direct dependencies from the requirements file
5866
+ * @returns {Promise<Array<Object>>} List of direct dependencies from the requirements file
5869
5867
  */
5870
5868
  async function parseReqData(reqFile, reqData = null, fetchDepsInfo = false) {
5871
5869
  const pkgList = [];
@@ -5892,179 +5890,187 @@ async function parseReqData(reqFile, reqData = null, fetchDepsInfo = false) {
5892
5890
  },
5893
5891
  }
5894
5892
  : undefined;
5895
- reqData
5896
- .replace(/\r/g, "")
5897
- .replace(/ [\\]\n/g, "")
5898
- .replace(/ {4}/g, " ")
5899
- .split("\n")
5900
- .forEach((l) => {
5901
- const properties = reqFile
5902
- ? [
5903
- {
5904
- name: "SrcFile",
5905
- value: reqFile,
5906
- },
5907
- ]
5908
- : [];
5909
- l = l.trim();
5910
- let markers;
5911
- if (l.includes(" ; ")) {
5912
- const tmpA = l.split(" ; ");
5913
- if (tmpA && tmpA.length === 2) {
5914
- l = tmpA[0];
5915
- markers = tmpA[1];
5893
+ const lines = reqData.replace(/\r/g, "").replace(/\\$/gm, "").split("\n");
5894
+ for (const line of lines) {
5895
+ let l = line.trim();
5896
+ if (l.includes("# Basic requirements")) {
5897
+ compScope = "required";
5898
+ } else if (l.includes("added by pip freeze")) {
5899
+ compScope = undefined;
5900
+ }
5901
+ if (l.startsWith("Skipping line") || l.startsWith("(add")) {
5902
+ continue;
5903
+ }
5904
+ if (!l || l.startsWith("#") || l.startsWith("-")) {
5905
+ continue;
5906
+ }
5907
+ const properties = reqFile
5908
+ ? [
5909
+ {
5910
+ name: "SrcFile",
5911
+ value: reqFile,
5912
+ },
5913
+ ]
5914
+ : [];
5915
+
5916
+ // Handle markers
5917
+ let markers = null;
5918
+ let structuredMarkers = null;
5919
+ if (l.includes(";")) {
5920
+ const parts = l.split(";");
5921
+ l = parts[0].trim();
5922
+ markers = parts.slice(1).join(";").trim();
5923
+ structuredMarkers = parseReqEnvMarkers(markers);
5924
+ }
5925
+
5926
+ // Handle extras (e.g., package[extra1,extra2])
5927
+ let extras = null;
5928
+ const extrasMatch = l.match(/^([a-zA-Z0-9_\-\.]+)(\[([^\]]+)\])?(.*)$/);
5929
+ if (extrasMatch) {
5930
+ const [, packageName, , extrasStr, versionSpecifiers] = extrasMatch;
5931
+ const name = packageName;
5932
+ if (extrasStr) {
5933
+ extras = extrasStr.split(",").map((e) => e.trim());
5934
+ l = `${name}${versionSpecifiers}`; // Reconstruct without extras for version parsing
5935
+ }
5936
+ if (PYTHON_STD_MODULES.includes(name)) {
5937
+ continue;
5938
+ }
5939
+ const versionMatch = versionSpecifiers.match(
5940
+ /(==|!=|<=|>=|<|>|~=)([0-9.a-zA-Z_*\-+]*)/,
5941
+ );
5942
+ let version = null;
5943
+ if (versionMatch) {
5944
+ version = versionMatch[2].replaceAll("*", "0") || null;
5945
+ if (version === "0") {
5946
+ version = null;
5916
5947
  }
5917
5948
  }
5918
- if (l.startsWith("Skipping line") || l.startsWith("(add")) {
5919
- return;
5949
+ const apkg = {
5950
+ name,
5951
+ version,
5952
+ scope: compScope,
5953
+ evidence,
5954
+ };
5955
+ if (extras && extras.length > 0) {
5956
+ properties.push({
5957
+ name: "cdx:pypi:extras",
5958
+ value: extras.join(","),
5959
+ });
5920
5960
  }
5921
- if (l.includes("# Basic requirements")) {
5922
- compScope = "required";
5923
- } else if (l.includes("added by pip freeze")) {
5924
- compScope = undefined;
5961
+ if (versionSpecifiers && !versionSpecifiers.startsWith("==")) {
5962
+ properties.push({
5963
+ name: "cdx:pypi:versionSpecifiers",
5964
+ value: versionSpecifiers.trim(),
5965
+ });
5925
5966
  }
5926
- if (!l.startsWith("#") && !l.startsWith("-")) {
5927
- if (l.includes(" ")) {
5928
- l = l.split(" ")[0];
5967
+ if (markers) {
5968
+ properties.push({
5969
+ name: "cdx:pip:markers",
5970
+ value: markers,
5971
+ });
5972
+ if (structuredMarkers && structuredMarkers.length > 0) {
5973
+ properties.push({
5974
+ name: "cdx:pip:structuredMarkers",
5975
+ value: JSON.stringify(structuredMarkers),
5976
+ });
5929
5977
  }
5930
- if (l.indexOf("=") > -1) {
5931
- const tmpA = l.split(/(==|<=|~=|>=)/);
5932
- let versionStr = tmpA[tmpA.length - 1].trim().replace("*", "0");
5933
- if (versionStr.indexOf(" ") > -1) {
5934
- versionStr = versionStr.split(" ")[0];
5935
- }
5936
- if (versionStr === "0") {
5937
- versionStr = null;
5938
- }
5939
- if (!tmpA[0].includes("=") && !tmpA[0].trim().includes(" ")) {
5940
- const name = tmpA[0].trim().replace(";", "");
5941
- const versionSpecifiers = l.replace(name, "");
5942
- if (!PYTHON_STD_MODULES.includes(name)) {
5943
- const apkg = {
5944
- name,
5945
- version: versionStr,
5946
- scope: compScope,
5947
- evidence,
5948
- };
5949
- if (
5950
- versionSpecifiers?.length > 0 &&
5951
- !versionSpecifiers.startsWith("==")
5952
- ) {
5953
- properties.push({
5954
- name: "cdx:pypi:versionSpecifiers",
5955
- value: versionSpecifiers,
5956
- });
5957
- }
5958
- if (markers) {
5959
- properties.push({
5960
- name: "cdx:pip:markers",
5961
- value: markers,
5962
- });
5963
- }
5964
- if (properties.length) {
5965
- apkg.properties = properties;
5966
- }
5967
- pkgList.push(apkg);
5968
- }
5969
- }
5970
- } else if (l.includes("<") && l.includes(">")) {
5971
- const tmpA = l.split(">");
5972
- const name = tmpA[0].trim().replace(";", "");
5973
- const versionSpecifiers = l.replace(name, "");
5974
- if (!PYTHON_STD_MODULES.includes(name)) {
5975
- pkgList.push({
5976
- name,
5977
- version: undefined,
5978
- scope: compScope,
5979
- evidence,
5980
- properties: [
5981
- ...properties,
5982
- {
5983
- name: "cdx:pypi:versionSpecifiers",
5984
- value: versionSpecifiers?.length
5985
- ? versionSpecifiers
5986
- : undefined,
5987
- },
5988
- ],
5989
- });
5990
- }
5991
- } else if (/[>|[@]/.test(l)) {
5992
- let tmpA = l.split(/(>|\[@)/);
5993
- if (tmpA.includes("#")) {
5994
- tmpA = tmpA.split("#")[0];
5995
- }
5996
- if (!tmpA[0].trim().includes(" ")) {
5997
- const name = tmpA[0].trim().replace(";", "");
5998
- const versionSpecifiers = l.replace(name, "");
5999
- if (!PYTHON_STD_MODULES.includes(name)) {
6000
- pkgList.push({
6001
- name,
6002
- version: undefined,
6003
- scope: compScope,
6004
- evidence,
6005
- properties: [
6006
- ...properties,
6007
- {
6008
- name: "cdx:pypi:versionSpecifiers",
6009
- value: versionSpecifiers?.length
6010
- ? versionSpecifiers
6011
- : undefined,
6012
- },
6013
- ],
6014
- });
6015
- }
6016
- }
6017
- } else if (l) {
6018
- if (l.includes("#")) {
6019
- l = l.split("#")[0];
6020
- }
6021
- l = l.trim();
6022
- const tmpA = l.split(/([<>])/);
6023
- if (tmpA && tmpA.length === 3) {
6024
- const name = tmpA[0].trim().replace(";", "");
6025
- const versionSpecifiers = l.replace(name, "");
6026
- if (!PYTHON_STD_MODULES.includes(name)) {
6027
- pkgList.push({
6028
- name,
6029
- version: undefined,
6030
- scope: compScope,
6031
- evidence,
6032
- properties: [
6033
- {
6034
- name: "cdx:pypi:versionSpecifiers",
6035
- value: versionSpecifiers?.length
6036
- ? versionSpecifiers
6037
- : undefined,
6038
- },
6039
- ],
6040
- });
6041
- }
6042
- } else if (!l.includes(" ")) {
6043
- const name = l.replace(";", "");
6044
- const versionSpecifiers = l.replace(name, "");
6045
- if (!PYTHON_STD_MODULES.includes(name)) {
6046
- pkgList.push({
6047
- name,
6048
- version: null,
6049
- scope: compScope,
6050
- evidence,
6051
- properties: [
6052
- {
6053
- name: "cdx:pypi:versionSpecifiers",
6054
- value: versionSpecifiers?.length
6055
- ? versionSpecifiers
6056
- : undefined,
6057
- },
6058
- ],
6059
- });
6060
- }
6061
- }
5978
+ }
5979
+ if (properties.length) {
5980
+ apkg.properties = properties;
5981
+ }
5982
+ pkgList.push(apkg);
5983
+ } else {
5984
+ const match = l.match(/^([a-zA-Z0-9_\-\.]+)(.*)$/);
5985
+ if (!match) {
5986
+ continue;
5987
+ }
5988
+ const [, name, versionSpecifiers] = match;
5989
+ if (PYTHON_STD_MODULES.includes(name)) {
5990
+ continue;
5991
+ }
5992
+ const versionMatch = versionSpecifiers.match(
5993
+ /(==|!=|<=|>=|<|>|~=)([0-9.a-zA-Z_*\-+]*)/,
5994
+ );
5995
+ let version = null;
5996
+ if (versionMatch) {
5997
+ version = versionMatch[2].replace("*", "0") || null;
5998
+ if (version === "0") version = null;
5999
+ }
6000
+ const apkg = {
6001
+ name,
6002
+ version,
6003
+ scope: compScope,
6004
+ evidence,
6005
+ };
6006
+ if (versionSpecifiers && !versionSpecifiers.startsWith("==")) {
6007
+ properties.push({
6008
+ name: "cdx:pypi:versionSpecifiers",
6009
+ value: versionSpecifiers.trim(),
6010
+ });
6011
+ }
6012
+ if (markers) {
6013
+ properties.push({
6014
+ name: "cdx:pip:markers",
6015
+ value: markers,
6016
+ });
6017
+ if (structuredMarkers && structuredMarkers.length > 0) {
6018
+ properties.push({
6019
+ name: "cdx:pip:structuredMarkers",
6020
+ value: JSON.stringify(structuredMarkers),
6021
+ });
6062
6022
  }
6063
6023
  }
6064
- });
6024
+ if (properties.length) {
6025
+ apkg.properties = properties;
6026
+ }
6027
+ pkgList.push(apkg);
6028
+ }
6029
+ }
6065
6030
  return await getPyMetadata(pkgList, fetchDepsInfo);
6066
6031
  }
6067
6032
 
6033
+ /**
6034
+ * Parse environment markers into structured format
6035
+ *
6036
+ * @param {String} markersStr Raw markers string
6037
+ * @returns {Array<Object>} Structured markers array
6038
+ */
6039
+ export function parseReqEnvMarkers(markersStr) {
6040
+ if (!markersStr) return [];
6041
+
6042
+ const markers = [];
6043
+ const tokens = markersStr
6044
+ .replace(/\s+/g, " ")
6045
+ .trim()
6046
+ .split(/\s+(and|or)\s+/gi)
6047
+ .filter((token) => token.trim());
6048
+ for (const token of tokens) {
6049
+ if (token.toLowerCase() === "and" || token.toLowerCase() === "or") {
6050
+ markers.push({
6051
+ operator: token.toLowerCase(),
6052
+ });
6053
+ } else {
6054
+ const match = token.match(
6055
+ /([a-zA-Z_]+)\s*(==|!=|<=|>=|<|>)\s*["']?([^"']*)["']?/,
6056
+ );
6057
+ if (match) {
6058
+ markers.push({
6059
+ variable: match[1],
6060
+ operator: match[2],
6061
+ value: match[3],
6062
+ });
6063
+ } else {
6064
+ // Add as raw token if parsing fails
6065
+ markers.push({
6066
+ raw: token,
6067
+ });
6068
+ }
6069
+ }
6070
+ }
6071
+ return markers;
6072
+ }
6073
+
6068
6074
  /**
6069
6075
  * Method to find python modules by parsing the imports and then checking with PyPI to obtain the latest version
6070
6076
  *
@@ -12350,10 +12356,14 @@ export function multiChecksumFile(algorithms, path) {
12350
12356
  const stream = createReadStream(path);
12351
12357
  stream.on("error", (err) => reject(err));
12352
12358
  stream.on("data", (chunk) =>
12353
- algorithms.forEach((alg) => hashes[alg].update(chunk)),
12359
+ algorithms.forEach((alg) => {
12360
+ hashes[alg].update(chunk);
12361
+ }),
12354
12362
  );
12355
12363
  stream.on("end", () => {
12356
- algorithms.forEach((alg) => (hashes[alg] = hashes[alg].digest("hex")));
12364
+ algorithms.forEach((alg) => {
12365
+ hashes[alg] = hashes[alg].digest("hex");
12366
+ });
12357
12367
  resolve(hashes);
12358
12368
  });
12359
12369
  });
@@ -13193,9 +13203,9 @@ export async function parsePodfileLock(podfileLock, projectPath) {
13193
13203
  }
13194
13204
  for (const [dependencyName, dependency] of dependencies) {
13195
13205
  if (dependency.dependencies) {
13196
- dependency.dependencies.forEach(
13197
- (dep) => (dep.name = dep.name.split("/")[0]),
13198
- );
13206
+ dependency.dependencies.forEach((dep) => {
13207
+ dep.name = dep.name.split("/")[0];
13208
+ });
13199
13209
  dependency.dependencies = [
13200
13210
  ...new Map(
13201
13211
  dependency.dependencies
@@ -13542,13 +13552,15 @@ async function fullScanCocoaPod(dependency, component, options) {
13542
13552
  if (podspec.authors) {
13543
13553
  component.authors = [];
13544
13554
  if (podspec.authors.constructor === Object) {
13545
- Object.entries(podspec.authors).forEach(([name, email]) =>
13555
+ Object.entries(podspec.authors).forEach(([name, email]) => {
13546
13556
  email.includes("@")
13547
13557
  ? component.authors.push({ name, email })
13548
- : component.authors.push({ name }),
13549
- );
13558
+ : component.authors.push({ name });
13559
+ });
13550
13560
  } else if (podspec.authors.constructor === Array) {
13551
- podspec.authors.forEach((name) => component.authors.push({ name }));
13561
+ podspec.authors.forEach((name) => {
13562
+ component.authors.push({ name });
13563
+ });
13552
13564
  } else {
13553
13565
  component.authors.push({ name: podspec.authors });
13554
13566
  }
@@ -14443,7 +14455,13 @@ export async function getPipFrozenTree(
14443
14455
  console.log(
14444
14456
  "Possible build errors detected with 'pip install'. Set the environment variable CDXGEN_DEBUG_MODE=debug to troubleshoot.",
14445
14457
  );
14446
- console.log(result.stderr.split("\n").slice(0, 5));
14458
+ if (result?.stderr?.includes("No module named pip")) {
14459
+ console.log(
14460
+ "Using uv? Run uv pip install command prior to running cdxgen.",
14461
+ );
14462
+ } else {
14463
+ console.log(result.stderr.split("\n").slice(0, 5));
14464
+ }
14447
14465
  }
14448
14466
  console.warn(
14449
14467
  "This project does not support python with version types. Use an appropriate container image such as `ghcr.io/appthreat/cdxgen-python39:v11` or `ghcr.io/appthreat/cdxgen-python311:v11` and invoke cdxgen with `-t python` instead.\n",
@@ -14534,13 +14552,19 @@ export async function getPipFrozenTree(
14534
14552
  "Installation of build dependencies failed. Perhaps the user is using the wrong cdxgen container image? Should I recommend raising a GitHub issue?",
14535
14553
  );
14536
14554
  }
14537
- console.log(
14538
- "Possible build errors detected. Set the environment variable CDXGEN_DEBUG_MODE=debug to troubleshoot.",
14539
- );
14540
14555
  // Bug #1640. result.stderr is null here despite the process erroring with a non-zero value.
14541
14556
  // How do we reproduce this with repo tests?
14542
14557
  if (result?.stderr) {
14543
- console.log(result.stderr?.split("\n")?.slice(0, 5));
14558
+ if (result?.stderr?.includes("No module named pip")) {
14559
+ console.log(
14560
+ "Using uv? Run uv pip install command prior to running cdxgen.",
14561
+ );
14562
+ } else {
14563
+ console.log(
14564
+ "Possible build errors detected. Set the environment variable CDXGEN_DEBUG_MODE=debug to troubleshoot.",
14565
+ );
14566
+ console.log(result.stderr?.split("\n")?.slice(0, 5));
14567
+ }
14544
14568
  }
14545
14569
  }
14546
14570
  }