Repository: CycloneDX/cdxgen (js)

Issue:
bom-ref missing when passing project name and version via cli args
When passing `--project-name some/repo --project-version some-version` via the cli, the `bom-ref` attribute is not populated.  This causes Dependency Track to not create a dependency graph for the project.

Removing these two cli args however will populate a `bom-ref` and the dependency graph.

Pull request:
Fix/issue 447
Fixes #447 - override project name and version for node.js projects

@setchy could you kindly test with this branch?

```
git clone https://github.com/CycloneDX/cdxgen.git
git checkout fix/issue-447
npm install
node bin/cdxgen.js -t js ...
```

Patch:
diff --git a/index.js b/index.js
index 6a34c74b..f76bbdb5 100644
--- a/index.js
+++ b/index.js
@@ -199,18 +199,25 @@ const createDefaultParentComponent = (path, type = "application") => {
 
 const determineParentComponent = (options) => {
   let parentComponent = undefined;
-  if (options.projectName && options.projectVersion) {
+  if (options.parentComponent && Object.keys(options.parentComponent).length) {
+    return options.parentComponent;
+  } else if (options.projectName && options.projectVersion) {
     parentComponent = {
       group: options.projectGroup || "",
       name: options.projectName,
       version: "" + options.projectVersion || "",
       type: "application"
     };
-  } else if (
-    options.parentComponent &&
-    Object.keys(options.parentComponent).length
-  ) {
-    return options.parentComponent;
+    const ppurl = new PackageURL(
+      parentComponent.type,
+      parentComponent.group,
+      parentComponent.name,
+      parentComponent.version,
+      null,
+      null
+    ).toString();
+    parentComponent["bom-ref"] = ppurl;
+    parentComponent["purl"] = decodeURIComponent(ppurl);
   }
   return parentComponent;
 };
@@ -324,6 +331,11 @@ function addMetadata(parentComponent = {}, format = "xml", options = {}) {
       delete parentComponent.evidence;
       delete parentComponent._integrity;
       delete parentComponent.license;
+      if (!parentComponent["purl"] && parentComponent["bom-ref"]) {
+        parentComponent["purl"] = decodeURIComponent(
+          parentComponent["bom-ref"]
+        );
+      }
     }
     if (parentComponent && parentComponent.components) {
       for (const comp of parentComponent.components) {
@@ -1788,9 +1800,9 @@ export const createNodejsBom = async (path, options) => {
           parentComponent.type = "application";
           ppurl = new PackageURL(
             "npm",
-            parentComponent.group,
-            parentComponent.name,
-            parentComponent.version,
+            options.projectGroup || parentComponent.group,
+            options.projectName || parentComponent.name,
+            options.projectVersion || parentComponent.version,
             null,
             null
           ).toString();
@@ -1808,9 +1820,9 @@ export const createNodejsBom = async (path, options) => {
         };
         ppurl = new PackageURL(
           "npm",
-          parentComponent.group,
-          parentComponent.name,
-          parentComponent.version,
+          options.projectGroup || parentComponent.group,
+          options.projectName || parentComponent.name,
+          options.projectVersion || parentComponent.version,
           null,
           null
         ).toString();
@@ -1839,11 +1851,10 @@ export const createNodejsBom = async (path, options) => {
         console.log(`Parsing ${f}`);
       }
       // Parse package-lock.json if available
-      const parsedList = await parsePkgLock(f);
+      const parsedList = await parsePkgLock(f, options);
       const dlist = parsedList.pkgList;
       const tmpParentComponent = dlist.splice(0, 1)[0] || {};
       tmpParentComponent.type = "application";
-      // Create a default parent component based on directory name
       if (!Object.keys(parentComponent).length) {
         parentComponent = tmpParentComponent;
       } else {
@@ -1931,9 +1942,9 @@ export const createNodejsBom = async (path, options) => {
           tmpParentComponent.type = "application";
           ppurl = new PackageURL(
             "npm",
-            tmpParentComponent.group,
-            tmpParentComponent.name,
-            tmpParentComponent.version,
+            options.projectGroup || tmpParentComponent.group,
+            options.projectName || tmpParentComponent.name,
+            options.projectVersion || tmpParentComponent.version,
             null,
             null
           ).toString();
@@ -1950,15 +1961,15 @@ export const createNodejsBom = async (path, options) => {
         const tmpA = dirName.split(sep);
         dirName = tmpA[tmpA.length - 1];
         const tmpParentComponent = {
-          group: "",
-          name: dirName,
+          group: options.projectGroup || "",
+          name: options.projectName || dirName,
           type: "application"
         };
         ppurl = new PackageURL(
           "npm",
           tmpParentComponent.group,
           tmpParentComponent.name,
-          tmpParentComponent.version,
+          options.projectVersion || tmpParentComponent.version,
           null,
           null
         ).toString();
@@ -2032,6 +2043,8 @@ export const createNodejsBom = async (path, options) => {
   if (parentSubComponents.length) {
     parentComponent.components = parentSubComponents;
   }
+  // We need to set this to force our version to be used rather than the directory name based one.
+  options.parentComponent = parentComponent;
   return buildBomNSData(options, pkgList, "npm", {
     allImports,
     src: path,
@@ -2309,13 +2322,22 @@ export const createPythonBom = async (path, options) => {
           parentComponent
         );
       }
-      const pdependencies = {
-        ref: parentComponent["bom-ref"],
-        dependsOn: Array.from(parentDependsOn).filter(
-          (r) => parentComponent && r !== parentComponent["bom-ref"]
-        )
-      };
-      dependencies.splice(0, 0, pdependencies);
+      let parentPresent = false;
+      for (const d of dependencies) {
+        if (d.ref === parentComponent["bom-ref"]) {
+          parentPresent = true;
+          break;
+        }
+      }
+      if (!parentPresent) {
+        const pdependencies = {
+          ref: parentComponent["bom-ref"],
+          dependsOn: Array.from(parentDependsOn).filter(
+            (r) => parentComponent && r !== parentComponent["bom-ref"]
+          )
+        };
+        dependencies.splice(0, 0, pdependencies);
+      }
     }
   }
   // Final fallback is to manually parse setup.py if we still
diff --git a/package-lock.json b/package-lock.json
index 4146bc08..42eadc97 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,16 +1,16 @@
 {
   "name": "@cyclonedx/cdxgen",
-  "version": "9.3.2",
+  "version": "9.3.3",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "@cyclonedx/cdxgen",
-      "version": "9.3.2",
+      "version": "9.3.3",
       "license": "Apache-2.0",
       "dependencies": {
-        "@babel/parser": "^7.22.5",
-        "@babel/traverse": "^7.22.5",
+        "@babel/parser": "^7.22.10",
+        "@babel/traverse": "^7.22.10",
         "ajv": "^8.12.0",
         "ajv-formats": "^2.1.1",
         "cheerio": "^1.0.0-rc.12",
@@ -38,7 +38,7 @@
       },
       "devDependencies": {
         "caxa": "^3.0.1",
-        "eslint": "^8.43.0",
+        "eslint": "^8.47.0",
         "jest": "^29.5.0",
         "prettier": "3.0.1"
       },
@@ -46,7 +46,7 @@
         "node": ">=16"
       },
       "optionalDependencies": {
-        "@appthreat/atom": "^1.0.0",
+        "@appthreat/atom": "^1.0.1",
         "@cyclonedx/cdxgen-plugins-bin": "^1.2.0",
         "body-parser": "^1.20.2",
         "compression": "^1.7.4",
@@ -76,9 +76,9 @@
       }
     },
     "node_modules/@appthreat/atom": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/@appthreat/atom/-/atom-1.0.0.tgz",
-      "integrity": "sha512-6p+Can1FcDPfZP8V+SSyqAPfkpXBG660SqdBXrxEvBLqtgBzjb5/wgx5ZF46YNUNJw/ELPvaALas9La0ioVRZg==",
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@appthreat/atom/-/atom-1.0.1.tgz",
+      "integrity": "sha512-c+CIIFdHw+0LVGp75qZh2MrU1Tah8CW5cCg9UvpfIkjduAmP2AEp+GfqOD8chJ6UFltWk50pFJILfBUUWyceZQ==",
       "optional": true,
       "dependencies": {
         "@babel/parser": "^7.22.5",
@@ -94,11 +94,12 @@
       }
     },
     "node_modules/@babel/code-frame": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
-      "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz",
+      "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==",
       "dependencies": {
-        "@babel/highlight": "^7.22.5"
+        "@babel/highlight": "^7.22.10",
+        "chalk": "^2.4.2"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -159,11 +160,11 @@
       }
     },
     "node_modules/@babel/generator": {
-      "version": "7.22.9",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz",
-      "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==",
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz",
+      "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==",
       "dependencies": {
-        "@babel/types": "^7.22.5",
+        "@babel/types": "^7.22.10",
         "@jridgewell/gen-mapping": "^0.3.2",
         "@jridgewell/trace-mapping": "^0.3.17",
         "jsesc": "^2.5.1"
@@ -334,12 +335,12 @@
       }
     },
     "node_modules/@babel/highlight": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
-      "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz",
+      "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==",
       "dependencies": {
         "@babel/helper-validator-identifier": "^7.22.5",
-        "chalk": "^2.0.0",
+        "chalk": "^2.4.2",
         "js-tokens": "^4.0.0"
       },
       "engines": {
@@ -347,9 +348,9 @@
       }
     },
     "node_modules/@babel/parser": {
-      "version": "7.22.7",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz",
-      "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==",
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz",
+      "integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==",
       "bin": {
         "parser": "bin/babel-parser.js"
       },
@@ -548,18 +549,18 @@
       }
     },
     "node_modules/@babel/traverse": {
-      "version": "7.22.8",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz",
-      "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==",
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz",
+      "integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==",
       "dependencies": {
-        "@babel/code-frame": "^7.22.5",
-        "@babel/generator": "^7.22.7",
+        "@babel/code-frame": "^7.22.10",
+        "@babel/generator": "^7.22.10",
         "@babel/helper-environment-visitor": "^7.22.5",
         "@babel/helper-function-name": "^7.22.5",
         "@babel/helper-hoist-variables": "^7.22.5",
         "@babel/helper-split-export-declaration": "^7.22.6",
-        "@babel/parser": "^7.22.7",
-        "@babel/types": "^7.22.5",
+        "@babel/parser": "^7.22.10",
+        "@babel/types": "^7.22.10",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
       },
@@ -568,9 +569,9 @@
       }
     },
     "node_modules/@babel/types": {
-      "version": "7.22.5",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
-      "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz",
+      "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==",
       "dependencies": {
         "@babel/helper-string-parser": "^7.22.5",
         "@babel/helper-validator-identifier": "^7.22.5",
@@ -617,9 +618,9 @@
       }
     },
     "node_modules/@eslint/eslintrc": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz",
-      "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==",
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
+      "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
       "dev": true,
       "dependencies": {
         "ajv": "^6.12.4",
@@ -656,9 +657,9 @@
       }
     },
     "node_modules/@eslint/eslintrc/node_modules/globals": {
-      "version": "13.20.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
-      "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
+      "version": "13.21.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz",
+      "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==",
       "dev": true,
       "dependencies": {
         "type-fest": "^0.20.2"
@@ -689,9 +690,9 @@
       }
     },
     "node_modules/@eslint/js": {
-      "version": "8.46.0",
-      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.46.0.tgz",
-      "integrity": "sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==",
+      "version": "8.47.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz",
+      "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==",
       "dev": true,
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -3244,15 +3245,15 @@
       }
     },
     "node_modules/eslint": {
-      "version": "8.46.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.46.0.tgz",
-      "integrity": "sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==",
+      "version": "8.47.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz",
+      "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==",
       "dev": true,
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.2.0",
         "@eslint-community/regexpp": "^4.6.1",
-        "@eslint/eslintrc": "^2.1.1",
-        "@eslint/js": "^8.46.0",
+        "@eslint/eslintrc": "^2.1.2",
+        "@eslint/js": "^8.47.0",
         "@humanwhocodes/config-array": "^0.11.10",
         "@humanwhocodes/module-importer": "^1.0.1",
         "@nodelib/fs.walk": "^1.2.8",
@@ -3263,7 +3264,7 @@
         "doctrine": "^3.0.0",
         "escape-string-regexp": "^4.0.0",
         "eslint-scope": "^7.2.2",
-        "eslint-visitor-keys": "^3.4.2",
+        "eslint-visitor-keys": "^3.4.3",
         "espree": "^9.6.1",
         "esquery": "^1.4.2",
         "esutils": "^2.0.2",
@@ -3314,9 +3315,9 @@
       }
     },
     "node_modules/eslint-visitor-keys": {
-      "version": "3.4.2",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz",
-      "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==",
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
       "dev": true,
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
diff --git a/package.json b/package.json
index d294827a..f5c75582 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@cyclonedx/cdxgen",
-  "version": "9.3.2",
+  "version": "9.3.3",
   "description": "Creates CycloneDX Software Bill-of-Materials (SBOM) from source or container image",
   "homepage": "http://github.com/cyclonedx/cdxgen",
   "author": "Prabhu Subramanian <prabhu@appthreat.com>",
@@ -50,8 +50,8 @@
     "url": "https://github.com/cyclonedx/cdxgen/issues"
   },
   "dependencies": {
-    "@babel/parser": "^7.22.5",
-    "@babel/traverse": "^7.22.5",
+    "@babel/parser": "^7.22.10",
+    "@babel/traverse": "^7.22.10",
     "ajv": "^8.12.0",
     "ajv-formats": "^2.1.1",
     "cheerio": "^1.0.0-rc.12",
@@ -75,7 +75,7 @@
     "yargs": "^17.7.2"
   },
   "optionalDependencies": {
-    "@appthreat/atom": "^1.0.0",
+    "@appthreat/atom": "^1.0.1",
     "@cyclonedx/cdxgen-plugins-bin": "^1.2.0",
     "body-parser": "^1.20.2",
     "compression": "^1.7.4",
@@ -88,7 +88,7 @@
   ],
   "devDependencies": {
     "caxa": "^3.0.1",
-    "eslint": "^8.43.0",
+    "eslint": "^8.47.0",
     "jest": "^29.5.0",
     "prettier": "3.0.1"
   }
diff --git a/utils.js b/utils.js
index 97962fa0..eb5692a2 100644
--- a/utils.js
+++ b/utils.js
@@ -497,12 +497,16 @@ export const parsePkgJson = async (pkgJsonFile) => {
  * Parse nodejs package lock file
  *
  * @param {string} pkgLockFile package-lock.json file
+ * @param {object} options Command line options
  */
-export const parsePkgLock = async (pkgLockFile) => {
+export const parsePkgLock = async (pkgLockFile, options = {}) => {
   let pkgList = [];
   const dependenciesList = [];
   const depKeys = {};
   let rootPkg = {};
+  if (!options) {
+    options = {};
+  }
   if (existsSync(pkgLockFile)) {
     const lockData = JSON.parse(readFileSync(pkgLockFile, "utf8"));
     rootPkg.name = lockData.name || "";
@@ -510,16 +514,16 @@ export const parsePkgLock = async (pkgLockFile) => {
     if (lockData.name && lockData.packages && lockData.packages[""]) {
       // Build the initial dependency tree for the root package
       rootPkg = {
-        group: "",
-        name: lockData.name,
-        version: lockData.version,
+        group: options.projectGroup || "",
+        name: options.projectName || lockData.name,
+        version: options.projectVersion || lockData.version,
         type: "application",
         "bom-ref": decodeURIComponent(
           new PackageURL(
             "npm",
-            "",
-            lockData.name,
-            lockData.version,
+            options.projectGroup || "",
+            options.projectName || lockData.name,
+            options.projectVersion || lockData.version,
             null,
             null
           ).toString()
@@ -531,10 +535,10 @@ export const parsePkgLock = async (pkgLockFile) => {
       dirName = tmpA[tmpA.length - 1];
       // v1 lock file
       rootPkg = {
-        group: "",
-        name: lockData.name || dirName,
-        version: lockData.version || "",
-        type: "application"
+        group: options.projectGroup || "",
+        name: options.projectName || lockData.name || dirName,
+        version: options.projectVersion || lockData.version || "",
+        type: "npm"
       };
     }
     if (rootPkg && rootPkg.name) {


Test patch:
diff --git a/.github/workflows/repotests.yml b/.github/workflows/repotests.yml
index 712eba27..0df8536f 100644
--- a/.github/workflows/repotests.yml
+++ b/.github/workflows/repotests.yml
@@ -11,12 +11,13 @@ on:
 
 jobs:
   build:
-    runs-on: ubuntu-latest
     if: "! contains(github.event.head_commit.message, '[ci skip]')"
     strategy:
+      fail-fast: false
       matrix:
         node-version: [18.x]
-
+        os: ['ubuntu-latest', 'windows-latest']
+    runs-on: ${{ matrix.os }}
     steps:
       - uses: actions/checkout@v3
       - name: Set up SBT
@@ -30,11 +31,14 @@ jobs:
         uses: actions/setup-node@v3
         with:
           node-version: ${{ matrix.node-version }}
-      - name: Install bazelisk
+      - name: Install bazelisk - linux
+        if: matrix.os == 'ubuntu-latest'
         run: |
           curl -LO "https://github.com/bazelbuild/bazelisk/releases/download/v1.15.0/bazelisk-linux-amd64"
           sudo mv bazelisk-linux-amd64 /usr/local/bin/bazel
-          sudo chmod +x /usr/local/bin/bazel
+      - name: Install bazelisk - windows
+        if: matrix.os == 'windows-latest'
+        run: choco install -y bazel
       - name: npm install, build and test
         run: |
           npm install
@@ -42,7 +46,8 @@ jobs:
           npm run lint
           npm test
           mkdir -p repotests
-          mkdir -p bomresults denoresults
+          mkdir -p bomresults 
+          mkdir -p denoresults
         env:
           CI: true
       - uses: swift-actions/setup-swift@v1
@@ -143,7 +148,7 @@ jobs:
           FETCH_LICENSE=true bin/cdxgen.js -p -r -t python repotests/DjanGoat -o bomresults/bom-python.json --validate --spec-version 1.4
           bin/cdxgen.js -p -r -t php repotests/Vulnerable-Web-Application -o bomresults/bom-php.json --validate --spec-version 1.4
       - name: denotests
-        if: github.ref == 'refs/heads/master'
+        if: github.ref == 'refs/heads/master' && matrix.os == 'ubuntu-latest'
         run: |
           docker build -t ghcr.io/cyclonedx/cdxgen-deno -f Dockerfile-deno .
           docker run --rm -t -e "CDXGEN_DEBUG_MODE=debug" -v $(pwd):/app ghcr.io/cyclonedx/cdxgen-deno -p -r -t java /app/repotests/shiftleft-java-example -o /app/denoresults/bom-java.json
diff --git a/utils.test.js b/utils.test.js
index 3872d9dd..10d4e7f0 100644
--- a/utils.test.js
+++ b/utils.test.js
@@ -1306,16 +1306,19 @@ test("parsePkgLock", async () => {
     version: "2.0.0"
   });
   expect(deps[deps.length - 1].name).toEqual("zone.js");
-  parsedList = await parsePkgLock("./test/data/package-lock-v3.json");
+  parsedList = await parsePkgLock("./test/data/package-lock-v3.json", {
+    projectVersion: "latest",
+    projectName: "cdxgen"
+  });
   deps = parsedList.pkgList;
   expect(deps.length).toEqual(879);
   expect(parsedList.dependenciesList.length).toEqual(879);
   expect(deps[0]).toEqual({
-    "bom-ref": "pkg:npm/@cyclonedx/cdxgen@8.4.3",
+    "bom-ref": "pkg:npm/cdxgen@latest",
     group: "",
-    name: "@cyclonedx/cdxgen",
+    name: "cdxgen",
     type: "application",
-    version: "8.4.3"
+    version: "latest"
   });
   expect(deps[deps.length - 1].name).toEqual("yocto-queue");
   parsedList = await parsePkgLock("./test/data/package-lock4.json");