@cdxgen/cdxgen 13.1.0 → 13.3.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.
- package/README.md +32 -15
- package/bin/cdxgen.js +243 -122
- package/bin/evinse.js +7 -0
- package/bin/sign.js +88 -14
- package/bin/tracebom.js +64 -4
- package/bin/validate.js +29 -7
- package/bin/verify.js +79 -39
- package/data/crypto-oid.json +88 -12
- package/data/remediations.json +47 -0
- package/data/rules/ai-bom.yaml +78 -0
- package/data/rules/cargo-rust.yaml +132 -0
- package/data/rules/mcp-servers.yaml +122 -0
- package/lib/audit/targets.js +6 -1
- package/lib/cli/bomAssembly.js +117 -15
- package/lib/cli/cliOptions.js +93 -1
- package/lib/cli/index.js +235 -5
- package/lib/cli/jsBom.js +108 -26
- package/lib/cli/jvmBom.js +68 -12
- package/lib/cli/managedBom.js +264 -41
- package/lib/cli/nativeBom.js +923 -15
- package/lib/core/activity.js +120 -2
- package/lib/core/env.js +44 -7
- package/lib/core/fs.js +174 -6
- package/lib/core/metadataProperties.js +97 -0
- package/lib/core/projectConfig.js +31 -4
- package/lib/core/userAgent.js +151 -0
- package/lib/ecosystems/bunutils.js +269 -101
- package/lib/ecosystems/cargoCache.js +364 -0
- package/lib/ecosystems/caxa.js +447 -7
- package/lib/ecosystems/cmakeResolver.js +66 -0
- package/lib/ecosystems/cppEvidence.js +104 -33
- package/lib/ecosystems/ecosystems.js +260 -99
- package/lib/ecosystems/golem.js +11 -1
- package/lib/ecosystems/gradleutils.js +185 -9
- package/lib/ecosystems/jsEvidence.js +19 -20
- package/lib/ecosystems/kosi.js +1263 -0
- package/lib/ecosystems/npmutils.js +110 -9
- package/lib/ecosystems/parsers-crystal.js +179 -0
- package/lib/ecosystems/parsers-dotnet.js +120 -49
- package/lib/ecosystems/parsers-elm.js +816 -0
- package/lib/ecosystems/parsers-gleam.js +1 -1
- package/lib/ecosystems/parsers-go.js +47 -9
- package/lib/ecosystems/parsers-js.js +171 -50
- package/lib/ecosystems/parsers-julia.js +268 -0
- package/lib/ecosystems/parsers-lua.js +218 -0
- package/lib/ecosystems/parsers-misc.js +919 -161
- package/lib/ecosystems/parsers-nim.js +221 -0
- package/lib/ecosystems/parsers-opam.js +180 -0
- package/lib/ecosystems/parsers-perl.js +277 -0
- package/lib/ecosystems/parsers-python.js +27 -15
- package/lib/ecosystems/parsers-r.js +148 -0
- package/lib/ecosystems/parsers-rebar.js +411 -0
- package/lib/ecosystems/parsers-rust.js +954 -33
- package/lib/ecosystems/parsers-spack.js +204 -0
- package/lib/ecosystems/parsers-stack.js +264 -0
- package/lib/ecosystems/parsers-terraform.js +194 -0
- package/lib/ecosystems/rubyutils.js +1426 -166
- package/lib/ecosystems/rusi.js +158 -7
- package/lib/evinser/evinser.js +547 -129
- package/lib/evinser/swiftsem.js +1914 -302
- package/lib/helpers/agenticToolutils.js +925 -0
- package/lib/helpers/bomSigner.js +652 -221
- package/lib/inventory/agentFormulationParser.js +57 -4
- package/lib/inventory/aiCollector.js +504 -10
- package/lib/inventory/aiInventory.js +12 -0
- package/lib/inventory/analyzer.js +488 -30
- package/lib/inventory/astWorker.js +6 -0
- package/lib/inventory/atomUtils.js +568 -31
- package/lib/inventory/auditCategories.js +8 -0
- package/lib/inventory/cbomutils.js +30 -0
- package/lib/inventory/cdxrs.js +110 -14
- package/lib/inventory/communityAiConfigParser.js +215 -2
- package/lib/inventory/depsUtils.js +183 -11
- package/lib/inventory/display.js +4 -5
- package/lib/inventory/dosai.js +627 -13
- package/lib/inventory/dynamic.js +39 -1
- package/lib/inventory/envcontext.js +9 -6
- package/lib/inventory/evidenceUtils.js +26 -5
- package/lib/inventory/fetchBatch.js +190 -19
- package/lib/inventory/fetchRate.js +74 -11
- package/lib/inventory/forgeEnricher.js +3 -2
- package/lib/inventory/jvmToolEnv.js +6 -5
- package/lib/inventory/mcpConfigParser.js +166 -2
- package/lib/inventory/mcpDiscovery.js +11 -0
- package/lib/inventory/mcpServerManifest.js +389 -0
- package/lib/inventory/mcpbBundle.js +419 -0
- package/lib/inventory/plugins.js +3 -0
- package/lib/inventory/protobom.js +62 -89
- package/lib/inventory/protobomLoader.js +4 -0
- package/lib/inventory/purl.js +152 -3
- package/lib/inventory/rustFormulationParser.js +1 -1
- package/lib/inventory/sbomDocument.js +2 -70
- package/lib/inventory/source.js +47 -23
- package/lib/inventory/stylePackageRefs.js +41 -0
- package/lib/inventory/svelteUtils.js +524 -0
- package/lib/inventory/traceRunner.js +210 -21
- package/lib/managers/binary.js +115 -24
- package/lib/managers/docker.js +440 -20
- package/lib/managers/oci.js +39 -1
- package/lib/parsers/cmakeLists.js +452 -0
- package/lib/parsers/huggingfaceUtils.js +15 -7
- package/lib/parsers/largeJson.js +454 -0
- package/lib/parsers/npmrc.js +19 -1
- package/lib/parsers/onnx.js +294 -0
- package/lib/parsers/safetensors.js +114 -0
- package/lib/stages/postgen/introspection/markers.js +29 -6
- package/lib/stages/postgen/postgen.js +237 -16
- package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +462 -0
- package/lib/validator/bomValidator.js +6 -16
- package/lib/validator/index.js +48 -10
- package/lib/validator/reporters/console.js +3 -0
- package/lib/validator/reporters/json.js +1 -0
- package/lib/validator/reporters/sarif.js +7 -0
- package/package.json +27 -27
- package/types/lib/audit/targets.d.ts.map +1 -1
- package/types/lib/cli/bomAssembly.d.ts +2 -1
- package/types/lib/cli/bomAssembly.d.ts.map +1 -1
- package/types/lib/cli/cliOptions.d.ts +33 -1
- package/types/lib/cli/cliOptions.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts +2 -2
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/cli/jsBom.d.ts +23 -0
- package/types/lib/cli/jsBom.d.ts.map +1 -1
- package/types/lib/cli/jvmBom.d.ts.map +1 -1
- package/types/lib/cli/managedBom.d.ts +33 -0
- package/types/lib/cli/managedBom.d.ts.map +1 -1
- package/types/lib/cli/nativeBom.d.ts +88 -8
- package/types/lib/cli/nativeBom.d.ts.map +1 -1
- package/types/lib/core/activity.d.ts.map +1 -1
- package/types/lib/core/env.d.ts +21 -0
- package/types/lib/core/env.d.ts.map +1 -1
- package/types/lib/core/fs.d.ts +55 -0
- package/types/lib/core/fs.d.ts.map +1 -1
- package/types/lib/core/metadataProperties.d.ts +39 -0
- package/types/lib/core/metadataProperties.d.ts.map +1 -0
- package/types/lib/core/projectConfig.d.ts +6 -2
- package/types/lib/core/projectConfig.d.ts.map +1 -1
- package/types/lib/core/userAgent.d.ts +56 -0
- package/types/lib/core/userAgent.d.ts.map +1 -0
- package/types/lib/ecosystems/bunutils.d.ts +12 -5
- package/types/lib/ecosystems/bunutils.d.ts.map +1 -1
- package/types/lib/ecosystems/cargoCache.d.ts +75 -0
- package/types/lib/ecosystems/cargoCache.d.ts.map +1 -0
- package/types/lib/ecosystems/caxa.d.ts +14 -0
- package/types/lib/ecosystems/caxa.d.ts.map +1 -1
- package/types/lib/ecosystems/cmakeResolver.d.ts +23 -0
- package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
- package/types/lib/ecosystems/cppEvidence.d.ts +2 -2
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/ecosystems.d.ts +15 -1
- package/types/lib/ecosystems/ecosystems.d.ts.map +1 -1
- package/types/lib/ecosystems/golem.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +40 -4
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/jsEvidence.d.ts +5 -2
- package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/kosi.d.ts +86 -0
- package/types/lib/ecosystems/kosi.d.ts.map +1 -0
- package/types/lib/ecosystems/npmutils.d.ts +42 -0
- package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-crystal.d.ts +27 -0
- package/types/lib/ecosystems/parsers-crystal.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-dotnet.d.ts +19 -0
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-elm.d.ts +79 -0
- package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-go.d.ts +10 -0
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-js.d.ts +10 -4
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-julia.d.ts +57 -0
- package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-lua.d.ts +50 -0
- package/types/lib/ecosystems/parsers-lua.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-misc.d.ts +90 -3
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-nim.d.ts +43 -0
- package/types/lib/ecosystems/parsers-nim.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-opam.d.ts +31 -0
- package/types/lib/ecosystems/parsers-opam.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-perl.d.ts +36 -0
- package/types/lib/ecosystems/parsers-perl.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-r.d.ts +35 -0
- package/types/lib/ecosystems/parsers-r.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-rebar.d.ts +42 -0
- package/types/lib/ecosystems/parsers-rebar.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-rust.d.ts +199 -0
- package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-spack.d.ts +33 -0
- package/types/lib/ecosystems/parsers-spack.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-stack.d.ts +35 -0
- package/types/lib/ecosystems/parsers-stack.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-terraform.d.ts +34 -0
- package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -0
- package/types/lib/ecosystems/pythonutils.d.ts +1 -1
- package/types/lib/ecosystems/rubyutils.d.ts +143 -2
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rusi.d.ts +13 -0
- package/types/lib/ecosystems/rusi.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +81 -2
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/evinser/swiftsem.d.ts +280 -15
- package/types/lib/evinser/swiftsem.d.ts.map +1 -1
- package/types/lib/helpers/agenticToolutils.d.ts +87 -0
- package/types/lib/helpers/agenticToolutils.d.ts.map +1 -0
- package/types/lib/helpers/bomSigner.d.ts +106 -13
- package/types/lib/helpers/bomSigner.d.ts.map +1 -1
- package/types/lib/inventory/agentFormulationParser.d.ts.map +1 -1
- package/types/lib/inventory/aiCollector.d.ts.map +1 -1
- package/types/lib/inventory/aiInventory.d.ts.map +1 -1
- package/types/lib/inventory/analyzer.d.ts.map +1 -1
- package/types/lib/inventory/atomUtils.d.ts +145 -3
- package/types/lib/inventory/atomUtils.d.ts.map +1 -1
- package/types/lib/inventory/auditCategories.d.ts +4 -0
- package/types/lib/inventory/auditCategories.d.ts.map +1 -1
- package/types/lib/inventory/cbomutils.d.ts.map +1 -1
- package/types/lib/inventory/cdxrs.d.ts +8 -3
- package/types/lib/inventory/cdxrs.d.ts.map +1 -1
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/depsUtils.d.ts +15 -0
- package/types/lib/inventory/depsUtils.d.ts.map +1 -1
- package/types/lib/inventory/display.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +87 -1
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/dynamic.d.ts.map +1 -1
- package/types/lib/inventory/envcontext.d.ts.map +1 -1
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
- package/types/lib/inventory/fetchBatch.d.ts +34 -0
- package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
- package/types/lib/inventory/fetchRate.d.ts +9 -6
- package/types/lib/inventory/fetchRate.d.ts.map +1 -1
- package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
- package/types/lib/inventory/jvmToolEnv.d.ts +5 -4
- package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -1
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/mcpDiscovery.d.ts.map +1 -1
- package/types/lib/inventory/mcpServerManifest.d.ts +19 -0
- package/types/lib/inventory/mcpServerManifest.d.ts.map +1 -0
- package/types/lib/inventory/mcpbBundle.d.ts +19 -0
- package/types/lib/inventory/mcpbBundle.d.ts.map +1 -0
- package/types/lib/inventory/plugins.d.ts.map +1 -1
- package/types/lib/inventory/protobom.d.ts +18 -13
- package/types/lib/inventory/protobom.d.ts.map +1 -1
- package/types/lib/inventory/protobomLoader.d.ts.map +1 -1
- package/types/lib/inventory/purl.d.ts +71 -2
- package/types/lib/inventory/purl.d.ts.map +1 -1
- package/types/lib/inventory/sbomDocument.d.ts.map +1 -1
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/inventory/stylePackageRefs.d.ts +17 -0
- package/types/lib/inventory/stylePackageRefs.d.ts.map +1 -0
- package/types/lib/inventory/svelteUtils.d.ts +124 -0
- package/types/lib/inventory/svelteUtils.d.ts.map +1 -0
- package/types/lib/inventory/traceRunner.d.ts +47 -1
- package/types/lib/inventory/traceRunner.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +30 -1
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +29 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/managers/oci.d.ts +14 -0
- package/types/lib/managers/oci.d.ts.map +1 -1
- package/types/lib/parsers/cmakeLists.d.ts +76 -0
- package/types/lib/parsers/cmakeLists.d.ts.map +1 -0
- package/types/lib/parsers/huggingfaceUtils.d.ts +8 -1
- package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -1
- package/types/lib/parsers/largeJson.d.ts +52 -0
- package/types/lib/parsers/largeJson.d.ts.map +1 -0
- package/types/lib/parsers/npmrc.d.ts +5 -0
- package/types/lib/parsers/npmrc.d.ts.map +1 -1
- package/types/lib/parsers/onnx.d.ts +28 -0
- package/types/lib/parsers/onnx.d.ts.map +1 -0
- package/types/lib/parsers/safetensors.d.ts +22 -0
- package/types/lib/parsers/safetensors.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/markers.d.ts +3 -2
- package/types/lib/stages/postgen/introspection/markers.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts +33 -0
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
- package/types/lib/validator/index.d.ts +10 -1
- package/types/lib/validator/index.d.ts.map +1 -1
- package/types/lib/validator/reporters/console.d.ts.map +1 -1
- package/types/lib/validator/reporters/json.d.ts.map +1 -1
- package/types/lib/validator/reporters/sarif.d.ts.map +1 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Buffer } from "node:buffer";
|
|
2
|
-
import { chmodSync } from "node:fs";
|
|
2
|
+
import { chmodSync, readFileSync } from "node:fs";
|
|
3
3
|
import { homedir, platform } from "node:os";
|
|
4
4
|
import { basename, join, resolve } from "node:path";
|
|
5
5
|
|
|
6
6
|
import { build } from "@cdxgen/cdx-purl";
|
|
7
|
+
import * as toml from "smol-toml";
|
|
7
8
|
|
|
8
9
|
import {
|
|
9
10
|
DEBUG_MODE,
|
|
@@ -23,7 +24,7 @@ import { thoughtLog } from "../core/logger.js";
|
|
|
23
24
|
import { isWin } from "../core/paths.js";
|
|
24
25
|
import { collectJarNS } from "../inventory/deps.js";
|
|
25
26
|
import { minimumGradleVersionForJava } from "../inventory/jvmToolEnv.js";
|
|
26
|
-
import { applyPurl } from "../inventory/purl.js";
|
|
27
|
+
import { applyPurl, tryBuildPurl } from "../inventory/purl.js";
|
|
27
28
|
import { parsePkgJson } from "./parsers-js.js";
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -40,19 +41,33 @@ function isJvmToolPinned() {
|
|
|
40
41
|
/**
|
|
41
42
|
* Method to return the gradle command to use.
|
|
42
43
|
*
|
|
44
|
+
* Project-local wrapper scripts (`gradlew`) are attacker-controlled files in
|
|
45
|
+
* the scanned project, so they are only used when dependency tooling is
|
|
46
|
+
* allowed (`options.installDeps !== false`); otherwise the system Gradle is
|
|
47
|
+
* used.
|
|
48
|
+
*
|
|
43
49
|
* @param {string} srcPath Path to look for gradlew wrapper
|
|
44
50
|
* @param {string|null} rootPath Root directory to look for gradlew wrapper
|
|
51
|
+
* @param {Object} [options] CLI options (`installDeps` gates wrapper use)
|
|
45
52
|
*/
|
|
46
|
-
export function getGradleCommand(srcPath, rootPath) {
|
|
53
|
+
export function getGradleCommand(srcPath, rootPath, options = {}) {
|
|
47
54
|
let gradleCmd = "gradle";
|
|
48
55
|
const pinnedToolSelected = isJvmToolPinned();
|
|
56
|
+
// Introspection mode exists to observe the project's own toolchain, so it
|
|
57
|
+
// keeps using wrappers even when dependency installation is disabled.
|
|
58
|
+
const allowProjectWrappers =
|
|
59
|
+
options.installDeps !== false || options.introspect === true;
|
|
49
60
|
|
|
50
61
|
let findGradleFile = "gradlew";
|
|
51
62
|
if (platform() === "win32") {
|
|
52
63
|
findGradleFile = "gradlew.bat";
|
|
53
64
|
}
|
|
54
65
|
|
|
55
|
-
if (
|
|
66
|
+
if (
|
|
67
|
+
allowProjectWrappers &&
|
|
68
|
+
!pinnedToolSelected &&
|
|
69
|
+
safeExistsSync(join(srcPath, findGradleFile))
|
|
70
|
+
) {
|
|
56
71
|
// Use local gradle wrapper if available
|
|
57
72
|
// Enable execute permission
|
|
58
73
|
try {
|
|
@@ -71,6 +86,7 @@ export function getGradleCommand(srcPath, rootPath) {
|
|
|
71
86
|
reason: `Selected project-local Gradle wrapper ${gradleCmd}.`,
|
|
72
87
|
});
|
|
73
88
|
} else if (
|
|
89
|
+
allowProjectWrappers &&
|
|
74
90
|
!pinnedToolSelected &&
|
|
75
91
|
rootPath &&
|
|
76
92
|
safeExistsSync(join(rootPath, findGradleFile))
|
|
@@ -379,8 +395,9 @@ export function executeParallelGradleProperties(
|
|
|
379
395
|
dir,
|
|
380
396
|
allProjectsStr,
|
|
381
397
|
extraArgs = [],
|
|
398
|
+
options = {},
|
|
382
399
|
) {
|
|
383
|
-
const gradleCmd = getGradleCommand(dir, null);
|
|
400
|
+
const gradleCmd = getGradleCommand(dir, null, options);
|
|
384
401
|
const gradleArgs = buildGradleCommandArguments(
|
|
385
402
|
extraArgs.concat(
|
|
386
403
|
readEnvironmentVariable("GRADLE_ARGS")
|
|
@@ -1204,11 +1221,16 @@ export async function collectGradleDependencies(
|
|
|
1204
1221
|
/**
|
|
1205
1222
|
* Method to return the mill command to use.
|
|
1206
1223
|
*
|
|
1224
|
+
* The project-local `mill` script is an attacker-controlled file in the
|
|
1225
|
+
* scanned project, so it is only used when dependency tooling is allowed
|
|
1226
|
+
* (`options.installDeps !== false`).
|
|
1227
|
+
*
|
|
1207
1228
|
* @param {string} srcPath Path to look for mill wrapper
|
|
1229
|
+
* @param {Object} [options] CLI options (`installDeps` gates wrapper use)
|
|
1208
1230
|
*/
|
|
1209
|
-
export function getMillCommand(srcPath) {
|
|
1231
|
+
export function getMillCommand(srcPath, options = {}) {
|
|
1210
1232
|
let millCmd = `mill${platform() === "win32" ? ".bat" : ""}`;
|
|
1211
|
-
if (safeExistsSync(join(srcPath, millCmd))) {
|
|
1233
|
+
if (options.installDeps !== false && safeExistsSync(join(srcPath, millCmd))) {
|
|
1212
1234
|
// Use local mill wrapper if available
|
|
1213
1235
|
// Enable execute permission
|
|
1214
1236
|
try {
|
|
@@ -1225,15 +1247,24 @@ export function getMillCommand(srcPath) {
|
|
|
1225
1247
|
/**
|
|
1226
1248
|
* Method to return the maven command to use.
|
|
1227
1249
|
*
|
|
1250
|
+
* Project-local wrapper scripts (`mvnw`) are attacker-controlled files in the
|
|
1251
|
+
* scanned project, so they are only used when dependency tooling is allowed
|
|
1252
|
+
* (`options.installDeps !== false`); otherwise the installed Maven is used.
|
|
1253
|
+
*
|
|
1228
1254
|
* @param {string} srcPath Path to look for maven wrapper
|
|
1229
1255
|
* @param {string} rootPath Root directory to look for maven wrapper
|
|
1256
|
+
* @param {Object} [options] CLI options (`installDeps` gates wrapper use)
|
|
1230
1257
|
*/
|
|
1231
|
-
export function getMavenCommand(srcPath, rootPath) {
|
|
1258
|
+
export function getMavenCommand(srcPath, rootPath, options = {}) {
|
|
1232
1259
|
let mavenCmd = "mvn";
|
|
1233
1260
|
// Check if the wrapper script is both available and functional
|
|
1234
1261
|
let isWrapperReady = false;
|
|
1235
1262
|
let isWrapperFound = false;
|
|
1236
1263
|
const pinnedToolSelected = isJvmToolPinned();
|
|
1264
|
+
// Introspection mode exists to observe the project's own toolchain, so it
|
|
1265
|
+
// keeps using wrappers even when dependency installation is disabled.
|
|
1266
|
+
const allowProjectWrappers =
|
|
1267
|
+
options.installDeps !== false || options.introspect === true;
|
|
1237
1268
|
let findMavenFile = "mvnw";
|
|
1238
1269
|
let mavenWrapperCmd = null;
|
|
1239
1270
|
if (platform() === "win32") {
|
|
@@ -1246,7 +1277,11 @@ export function getMavenCommand(srcPath, rootPath) {
|
|
|
1246
1277
|
}
|
|
1247
1278
|
}
|
|
1248
1279
|
|
|
1249
|
-
if (
|
|
1280
|
+
if (
|
|
1281
|
+
allowProjectWrappers &&
|
|
1282
|
+
!pinnedToolSelected &&
|
|
1283
|
+
safeExistsSync(join(srcPath, findMavenFile))
|
|
1284
|
+
) {
|
|
1250
1285
|
// Use local maven wrapper if available
|
|
1251
1286
|
// Enable execute permission
|
|
1252
1287
|
try {
|
|
@@ -1266,6 +1301,7 @@ export function getMavenCommand(srcPath, rootPath) {
|
|
|
1266
1301
|
reason: `Found Maven wrapper candidate ${mavenWrapperCmd}.`,
|
|
1267
1302
|
});
|
|
1268
1303
|
} else if (
|
|
1304
|
+
allowProjectWrappers &&
|
|
1269
1305
|
!pinnedToolSelected &&
|
|
1270
1306
|
rootPath &&
|
|
1271
1307
|
safeExistsSync(join(rootPath, findMavenFile))
|
|
@@ -1386,3 +1422,143 @@ export function getMavenCommand(srcPath, rootPath) {
|
|
|
1386
1422
|
}
|
|
1387
1423
|
return mavenCmd;
|
|
1388
1424
|
}
|
|
1425
|
+
|
|
1426
|
+
/**
|
|
1427
|
+
* Parse a Gradle version catalog (`gradle/libs.versions.toml`).
|
|
1428
|
+
*
|
|
1429
|
+
* A catalog declares coordinates the build scripts then reference by alias.
|
|
1430
|
+
* It is a declaration, not a resolution: entries may go unused, and their
|
|
1431
|
+
* versions may be references into the `[versions]` table. Because of that,
|
|
1432
|
+
* catalog components are emitted only as a fallback when Gradle itself
|
|
1433
|
+
* produced no dependency information, and every component carries a
|
|
1434
|
+
* `cdx:gradle:catalog=true` property so consumers can tell declared catalog
|
|
1435
|
+
* entries from a resolved graph.
|
|
1436
|
+
*
|
|
1437
|
+
* Only libraries whose version resolves to a literal (inline or via
|
|
1438
|
+
* `version.ref`) are emitted; rich or unresolved versions would produce purls
|
|
1439
|
+
* that identify no artifact. Plugins are skipped because they are build-time
|
|
1440
|
+
* only.
|
|
1441
|
+
*
|
|
1442
|
+
* @param {string} catalogFile Path to `libs.versions.toml`
|
|
1443
|
+
* @returns {Object[]} Package records for resolvable library entries
|
|
1444
|
+
*/
|
|
1445
|
+
export function parseGradleVersionCatalog(catalogFile) {
|
|
1446
|
+
let catalog;
|
|
1447
|
+
try {
|
|
1448
|
+
catalog = toml.parse(readFileSync(catalogFile, "utf-8"));
|
|
1449
|
+
} catch (error) {
|
|
1450
|
+
console.warn(`Failed to parse ${catalogFile}: ${error.message}`);
|
|
1451
|
+
return [];
|
|
1452
|
+
}
|
|
1453
|
+
const versions =
|
|
1454
|
+
catalog?.versions && typeof catalog.versions === "object"
|
|
1455
|
+
? catalog.versions
|
|
1456
|
+
: {};
|
|
1457
|
+
const libraries =
|
|
1458
|
+
catalog?.libraries && typeof catalog.libraries === "object"
|
|
1459
|
+
? catalog.libraries
|
|
1460
|
+
: {};
|
|
1461
|
+
const pkgList = [];
|
|
1462
|
+
for (const entry of Object.values(libraries)) {
|
|
1463
|
+
const coordinate = catalogCoordinate(entry);
|
|
1464
|
+
if (!coordinate) {
|
|
1465
|
+
continue;
|
|
1466
|
+
}
|
|
1467
|
+
const version = resolveCatalogVersion(entry, versions);
|
|
1468
|
+
if (!version) {
|
|
1469
|
+
continue;
|
|
1470
|
+
}
|
|
1471
|
+
const { group, name } = coordinate;
|
|
1472
|
+
// A catalog is authored input, but a malformed coordinate must cost the
|
|
1473
|
+
// one entry, not the whole scan.
|
|
1474
|
+
const purl = tryBuildPurl({
|
|
1475
|
+
type: "maven",
|
|
1476
|
+
namespace: group,
|
|
1477
|
+
name,
|
|
1478
|
+
version,
|
|
1479
|
+
});
|
|
1480
|
+
if (!purl) {
|
|
1481
|
+
continue;
|
|
1482
|
+
}
|
|
1483
|
+
pkgList.push({
|
|
1484
|
+
group,
|
|
1485
|
+
name,
|
|
1486
|
+
version,
|
|
1487
|
+
type: "library",
|
|
1488
|
+
scope: "required",
|
|
1489
|
+
purl,
|
|
1490
|
+
"bom-ref": decodeURIComponent(purl),
|
|
1491
|
+
properties: [
|
|
1492
|
+
{ name: "internal:SrcFile", value: catalogFile },
|
|
1493
|
+
{ name: "cdx:gradle:catalog", value: "true" },
|
|
1494
|
+
],
|
|
1495
|
+
evidence: {
|
|
1496
|
+
identity: {
|
|
1497
|
+
field: "purl",
|
|
1498
|
+
confidence: 0.5,
|
|
1499
|
+
methods: [
|
|
1500
|
+
{
|
|
1501
|
+
technique: "source-code-analysis",
|
|
1502
|
+
confidence: 0.5,
|
|
1503
|
+
value: `Filename ${catalogFile}`,
|
|
1504
|
+
},
|
|
1505
|
+
],
|
|
1506
|
+
},
|
|
1507
|
+
},
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
return pkgList;
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
/**
|
|
1514
|
+
* Read the Maven coordinate of one catalog entry.
|
|
1515
|
+
*
|
|
1516
|
+
* A catalog writes the coordinate either as `module = "group:name"` or as a
|
|
1517
|
+
* separate `group` and `name` pair; both forms are equivalent and both appear
|
|
1518
|
+
* in real catalogs.
|
|
1519
|
+
*
|
|
1520
|
+
* @param {object} entry Catalog library entry
|
|
1521
|
+
* @returns {{group: string, name: string}|undefined} Coordinate, or undefined
|
|
1522
|
+
*/
|
|
1523
|
+
function catalogCoordinate(entry) {
|
|
1524
|
+
const module = typeof entry?.module === "string" ? entry.module : undefined;
|
|
1525
|
+
if (module?.includes(":")) {
|
|
1526
|
+
const separator = module.indexOf(":");
|
|
1527
|
+
return {
|
|
1528
|
+
group: module.slice(0, separator),
|
|
1529
|
+
name: module.slice(separator + 1),
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
if (typeof entry?.group === "string" && typeof entry?.name === "string") {
|
|
1533
|
+
return { group: entry.group, name: entry.name };
|
|
1534
|
+
}
|
|
1535
|
+
return undefined;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
/**
|
|
1539
|
+
* Resolve the version of one catalog entry.
|
|
1540
|
+
*
|
|
1541
|
+
* An entry may pin `version = "1.2.3"` directly or reference the versions
|
|
1542
|
+
* table with `version.ref = "alias"`. Version references that are missing, or
|
|
1543
|
+
* that carry Gradle rich-version syntax (ranges, `!!`, separators), resolve
|
|
1544
|
+
* to nothing and the entry is skipped.
|
|
1545
|
+
*
|
|
1546
|
+
* @param {object} entry Catalog library entry
|
|
1547
|
+
* @param {object} versions Parsed `[versions]` table
|
|
1548
|
+
* @returns {string|undefined} Concrete version, or undefined
|
|
1549
|
+
*/
|
|
1550
|
+
function resolveCatalogVersion(entry, versions) {
|
|
1551
|
+
const raw =
|
|
1552
|
+
typeof entry?.version === "string"
|
|
1553
|
+
? entry.version
|
|
1554
|
+
: typeof entry?.version?.ref === "string"
|
|
1555
|
+
? versions[entry.version.ref]
|
|
1556
|
+
: undefined;
|
|
1557
|
+
if (typeof raw !== "string" || !raw) {
|
|
1558
|
+
return undefined;
|
|
1559
|
+
}
|
|
1560
|
+
if (/[[\](),!]|->|\.\./u.test(raw)) {
|
|
1561
|
+
return undefined;
|
|
1562
|
+
}
|
|
1563
|
+
return raw;
|
|
1564
|
+
}
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
|
|
9
9
|
import { join, resolve } from "node:path";
|
|
10
10
|
|
|
11
|
-
import { DEBUG_MODE } from "../core/activity.js";
|
|
12
11
|
import { safeExistsSync } from "../core/fs.js";
|
|
13
12
|
import { createOccurrenceEvidence } from "../inventory/evidenceUtils.js";
|
|
13
|
+
import { isPkgTypeOnlyImport, setNpmTypeOnlyProperty } from "./npmutils.js";
|
|
14
14
|
import { parsePkgJson } from "./parsers-js.js";
|
|
15
15
|
|
|
16
16
|
const NPM_BIN_IMPORT_PREFIX = "cdx:npm:bin/";
|
|
@@ -109,8 +109,11 @@ function applyNpmBinCommandEvidence(pkg, allImports) {
|
|
|
109
109
|
*
|
|
110
110
|
* For each component, resolves its module aliases (including the deno jsr
|
|
111
111
|
* specifier), records imported/exported modules as properties, attaches
|
|
112
|
-
* occurrence evidence, and
|
|
113
|
-
* package is used
|
|
112
|
+
* occurrence evidence, and promotes the component scope to "required" when the
|
|
113
|
+
* package is used. A package with no observed usage keeps the scope its
|
|
114
|
+
* manifest parser assigned: static import analysis cannot see packages loaded
|
|
115
|
+
* from configuration, bundler entrypoints, stylesheets, or plugins, so a
|
|
116
|
+
* missing import is not evidence that a package is optional.
|
|
114
117
|
*
|
|
115
118
|
* @param {Array<object>} pkgList Package components to enrich.
|
|
116
119
|
* @param {object} allImports Map of import specifier to usage evidence objects.
|
|
@@ -128,10 +131,6 @@ export async function addEvidenceForImports(
|
|
|
128
131
|
const impPkgs = Object.keys(allImports);
|
|
129
132
|
const exportedPkgs = Object.keys(allExports);
|
|
130
133
|
for (const pkg of pkgList) {
|
|
131
|
-
if (impPkgs?.length) {
|
|
132
|
-
// Assume that all packages are optional until we see an evidence
|
|
133
|
-
pkg.scope = "optional";
|
|
134
|
-
}
|
|
135
134
|
const { group, name } = pkg;
|
|
136
135
|
// Evidence belonging to a type must be associated with the package
|
|
137
136
|
if (group === "@types") {
|
|
@@ -155,7 +154,6 @@ export async function addEvidenceForImports(
|
|
|
155
154
|
aliases.push(jsrSpecifier);
|
|
156
155
|
}
|
|
157
156
|
}
|
|
158
|
-
let isImported = false;
|
|
159
157
|
for (const alias of aliases) {
|
|
160
158
|
const isWasmAlias = /\.wasm([?#].*)?$/i.test(alias);
|
|
161
159
|
const all_includes = impPkgs.filter(
|
|
@@ -213,11 +211,22 @@ export async function addEvidenceForImports(
|
|
|
213
211
|
}
|
|
214
212
|
// Identify all the imported modules of a component
|
|
215
213
|
if (impPkgs.includes(alias) || all_includes.length) {
|
|
216
|
-
isImported = true;
|
|
217
214
|
let importedModules = new Set();
|
|
218
215
|
let wasmExportedModules = new Set();
|
|
219
216
|
const seenOccurrenceLocations = new Set();
|
|
220
|
-
|
|
217
|
+
// A package imported only for its types is erased at compile time.
|
|
218
|
+
// Scoping it excluded here, rather than when the BOM is assembled,
|
|
219
|
+
// keeps propagateRequiredScopeFromDependencies from promoting what it
|
|
220
|
+
// depends on. A package whose bin command is used is still required.
|
|
221
|
+
if (
|
|
222
|
+
isPkgTypeOnlyImport(allImports, group, name) &&
|
|
223
|
+
!getNpmBinCommandEvidenceKeys(allImports, pkg).length
|
|
224
|
+
) {
|
|
225
|
+
pkg.scope = "excluded";
|
|
226
|
+
setNpmTypeOnlyProperty(pkg);
|
|
227
|
+
} else {
|
|
228
|
+
pkg.scope = "required";
|
|
229
|
+
}
|
|
221
230
|
for (const subevidence of all_includes) {
|
|
222
231
|
const evidences = allImports[subevidence];
|
|
223
232
|
for (const evidence of evidences) {
|
|
@@ -273,16 +282,6 @@ export async function addEvidenceForImports(
|
|
|
273
282
|
}
|
|
274
283
|
break;
|
|
275
284
|
}
|
|
276
|
-
if (
|
|
277
|
-
impPkgs?.length > 0 &&
|
|
278
|
-
!isImported &&
|
|
279
|
-
DEBUG_MODE &&
|
|
280
|
-
pkg?.scope !== "optional"
|
|
281
|
-
) {
|
|
282
|
-
console.debug(
|
|
283
|
-
`\x1b[1;35mNotice: Package ${pkg.name} has no usage in code. Check if it is needed.\x1b[0m`,
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
285
|
// Capture metadata such as description from local node_modules in deep mode
|
|
287
286
|
if (deep && !pkg.description && pkg.properties) {
|
|
288
287
|
let localNodeModulesPath;
|