@cyclonedx/cdxgen 9.9.8 → 9.9.9

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 CHANGED
@@ -371,6 +371,7 @@ cdxgen can retain the dependency tree under the `dependencies` attribute for a s
371
371
  | GRADLE_DEPENDENCY_TASK | By default cdxgen use the task "dependencies" to collect packages. Set to override the task name. |
372
372
  | SBT_CACHE_DIR | Specify sbt cache directory. Useful for class name resolving |
373
373
  | FETCH_LICENSE | Set this variable to `true` or `1` to fetch license information from the registry. npm and golang |
374
+ | SEARCH_MAVEN_ORG | If maven metadata is missing in jar file, a search is performed on search.maven.org. Set to `false` or `0` to disable search. |
374
375
  | USE_GOSUM | Set to `true` or `1` to generate BOMs for golang projects using go.sum as the dependency source of truth, instead of go.mod |
375
376
  | CDXGEN_TIMEOUT_MS | Default timeout for known execution involving maven, gradle or sbt |
376
377
  | CDXGEN_SERVER_TIMEOUT_MS | Default timeout in server mode |
package/index.js CHANGED
@@ -1085,7 +1085,7 @@ export const createJarBom = async (path, options) => {
1085
1085
  if (DEBUG_MODE) {
1086
1086
  console.log(`Parsing ${jar}`);
1087
1087
  }
1088
- const dlist = extractJarArchive(jar, tempDir);
1088
+ const dlist = await extractJarArchive(jar, tempDir);
1089
1089
  if (dlist && dlist.length) {
1090
1090
  pkgList = pkgList.concat(dlist);
1091
1091
  }
@@ -1127,7 +1127,7 @@ export const createJavaBom = async (path, options) => {
1127
1127
  }
1128
1128
  const tempDir = mkdtempSync(join(tmpdir(), "war-deps-"));
1129
1129
  jarNSMapping = collectJarNS(tempDir);
1130
- pkgList = extractJarArchive(path, tempDir, jarNSMapping);
1130
+ pkgList = await extractJarArchive(path, tempDir, jarNSMapping);
1131
1131
  if (pkgList.length) {
1132
1132
  pkgList = await getMvnMetadata(pkgList);
1133
1133
  }
@@ -3560,7 +3560,7 @@ export const createJenkinsBom = async (path, options) => {
3560
3560
  if (DEBUG_MODE) {
3561
3561
  console.log(`Parsing ${f}`);
3562
3562
  }
3563
- const dlist = extractJarArchive(f, tempDir);
3563
+ const dlist = await extractJarArchive(f, tempDir);
3564
3564
  if (dlist && dlist.length) {
3565
3565
  pkgList = pkgList.concat(dlist);
3566
3566
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyclonedx/cdxgen",
3
- "version": "9.9.8",
3
+ "version": "9.9.9",
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>",
package/utils.js CHANGED
@@ -19,8 +19,10 @@ import {
19
19
  readFileSync,
20
20
  rmSync,
21
21
  unlinkSync,
22
- writeFileSync
22
+ writeFileSync,
23
+ createReadStream
23
24
  } from "node:fs";
25
+ import { createHash } from "node:crypto";
24
26
  import got from "got";
25
27
  import Arborist from "@npmcli/arborist";
26
28
  import path from "node:path";
@@ -120,6 +122,19 @@ export const FETCH_LICENSE =
120
122
  process.env.FETCH_LICENSE &&
121
123
  ["true", "1"].includes(process.env.FETCH_LICENSE);
122
124
 
125
+ // Wether search.maven.org will be used to identify jars without maven metadata; default, if unset shall be 'true'
126
+ export const SEARCH_MAVEN_ORG =
127
+ !process.env.SEARCH_MAVEN_ORG ||
128
+ ["true", "1"].includes(process.env.SEARCH_MAVEN_ORG);
129
+
130
+ // circuit breaker for search maven.org
131
+ let search_maven_org_errors = 0;
132
+ const MAX_SEARCH_MAVEN_ORG_ERRORS = 5;
133
+
134
+ // circuit breaker for get repo license
135
+ let get_repo_license_errors = 0;
136
+ const MAX_GET_REPO_LICENSE_ERRORS = 5;
137
+
123
138
  const MAX_LICENSE_ID_LENGTH = 100;
124
139
 
125
140
  let PYTHON_CMD = "python";
@@ -3353,7 +3368,7 @@ export const toGitHubApiUrl = function (repoUrl, repoMetadata) {
3353
3368
  export const getRepoLicense = async function (repoUrl, repoMetadata) {
3354
3369
  let apiUrl = toGitHubApiUrl(repoUrl, repoMetadata);
3355
3370
  // Perform github lookups
3356
- if (apiUrl) {
3371
+ if (apiUrl && get_repo_license_errors < MAX_GET_REPO_LICENSE_ERRORS) {
3357
3372
  let licenseUrl = apiUrl + "/license";
3358
3373
  const headers = {};
3359
3374
  if (process.env.GITHUB_TOKEN) {
@@ -3399,8 +3414,10 @@ export const getRepoLicense = async function (repoUrl, repoMetadata) {
3399
3414
  "Please ensure GITHUB_TOKEN is set as environment variable. " +
3400
3415
  "See: https://docs.github.com/en/rest/overview/rate-limits-for-the-rest-api"
3401
3416
  );
3417
+ get_repo_license_errors++;
3402
3418
  } else if (!err.message.includes("404")) {
3403
3419
  console.log(err);
3420
+ get_repo_license_errors++;
3404
3421
  }
3405
3422
  }
3406
3423
  }
@@ -6775,6 +6792,22 @@ export const getPomPropertiesFromMavenDir = function (mavenDir) {
6775
6792
  return pomProperties;
6776
6793
  };
6777
6794
 
6795
+ /**
6796
+ *
6797
+ * @param {string} hashName name of hash algorithm
6798
+ * @param {string} path path to file
6799
+ * @returns {Promise<String>} hex value of hash
6800
+ */
6801
+ async function checksumFile(hashName, path) {
6802
+ return new Promise((resolve, reject) => {
6803
+ const hash = createHash(hashName);
6804
+ const stream = createReadStream(path);
6805
+ stream.on("error", (err) => reject(err));
6806
+ stream.on("data", (chunk) => hash.update(chunk));
6807
+ stream.on("end", () => resolve(hash.digest("hex")));
6808
+ });
6809
+ }
6810
+
6778
6811
  /**
6779
6812
  * Method to extract a war or ear file
6780
6813
  *
@@ -6784,7 +6817,7 @@ export const getPomPropertiesFromMavenDir = function (mavenDir) {
6784
6817
  *
6785
6818
  * @return pkgList Package list
6786
6819
  */
6787
- export const extractJarArchive = function (
6820
+ export const extractJarArchive = async function (
6788
6821
  jarFile,
6789
6822
  tempDir,
6790
6823
  jarNSMapping = {}
@@ -6882,6 +6915,35 @@ export const extractJarArchive = function (
6882
6915
  version = pomProperties["version"],
6883
6916
  confidence = 1,
6884
6917
  technique = "manifest-analysis";
6918
+ if (
6919
+ (!group || !name || !version) &&
6920
+ SEARCH_MAVEN_ORG &&
6921
+ search_maven_org_errors < MAX_SEARCH_MAVEN_ORG_ERRORS
6922
+ ) {
6923
+ try {
6924
+ const sha = await checksumFile("sha1", jf);
6925
+ const searchurl =
6926
+ "https://search.maven.org/solrsearch/select?q=1:%22" +
6927
+ sha +
6928
+ "%22&rows=20&wt=json";
6929
+ const res = await cdxgenAgent.get(searchurl, {
6930
+ responseType: "json"
6931
+ });
6932
+ const data = res && res.body ? res.body["response"] : undefined;
6933
+ if (data && data["numFound"] == 1) {
6934
+ const jarInfo = data["docs"][0];
6935
+ group = jarInfo["g"];
6936
+ name = jarInfo["a"];
6937
+ version = jarInfo["v"];
6938
+ technique = "hash-comparison";
6939
+ }
6940
+ } catch (err) {
6941
+ if (err && err.message && !err.message.includes("404")) {
6942
+ console.log(err);
6943
+ search_maven_org_errors++;
6944
+ }
6945
+ }
6946
+ }
6885
6947
  if ((!group || !name || !version) && existsSync(manifestFile)) {
6886
6948
  confidence = 0.8;
6887
6949
  const jarMetadata = parseJarManifest(