@cdxgen/cdxgen 13.2.0 → 13.4.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 +33 -14
- package/bin/cdxgen.js +310 -138
- package/bin/evinse.js +22 -0
- package/bin/repl.js +86 -0
- package/bin/sign.js +119 -15
- package/bin/tracebom.js +69 -5
- package/bin/validate.js +107 -19
- package/bin/verify.js +172 -63
- package/data/helpers/init.gradle +46 -21
- package/data/remediations.json +85 -0
- package/data/rules/dependency-sources.yaml +67 -0
- package/data/rules/scala-evidence.yaml +115 -0
- package/lib/audit/index.js +38 -6
- package/lib/cli/bomAssembly.js +105 -15
- package/lib/cli/cliOptions.js +93 -1
- package/lib/cli/index.js +156 -58
- package/lib/cli/jsBom.js +99 -53
- package/lib/cli/jvmBom.js +708 -147
- package/lib/cli/managedBom.js +415 -224
- package/lib/cli/nativeBom.js +264 -44
- package/lib/core/activity.js +12 -0
- package/lib/core/env.js +22 -15
- package/lib/core/fs.js +176 -7
- package/lib/core/httpClient.js +159 -24
- package/lib/core/metadataProperties.js +97 -0
- package/lib/core/pluginRun.js +184 -0
- package/lib/core/processTree.js +100 -0
- package/lib/core/projectConfig.js +31 -4
- package/lib/core/runState.js +39 -0
- package/lib/core/toml.js +72 -0
- package/lib/ecosystems/asarutils.js +4 -2
- package/lib/ecosystems/bunutils.js +274 -108
- package/lib/ecosystems/cargoCache.js +231 -8
- package/lib/ecosystems/caxa.js +434 -2
- package/lib/ecosystems/cmakeResolver.js +76 -21
- package/lib/ecosystems/cppBuildContext.js +631 -0
- package/lib/ecosystems/cppEvidence.js +399 -51
- package/lib/ecosystems/cppIncludeResolver.js +294 -0
- package/lib/ecosystems/denoutils.js +93 -66
- package/lib/ecosystems/ecosystems.js +1983 -793
- package/lib/ecosystems/golem.js +28 -12
- package/lib/ecosystems/gradleutils.js +356 -37
- package/lib/ecosystems/jsEvidence.js +104 -44
- package/lib/ecosystems/kosi.js +31 -7
- package/lib/ecosystems/npmutils.js +174 -9
- package/lib/ecosystems/parsers-dotnet.js +616 -159
- package/lib/ecosystems/parsers-elm.js +46 -28
- package/lib/ecosystems/parsers-gleam.js +3 -4
- package/lib/ecosystems/parsers-go.js +371 -70
- package/lib/ecosystems/parsers-js.js +263 -76
- package/lib/ecosystems/parsers-julia.js +2 -3
- package/lib/ecosystems/parsers-jvm.js +204 -12
- package/lib/ecosystems/parsers-misc.js +929 -216
- package/lib/ecosystems/parsers-python.js +167 -24
- package/lib/ecosystems/parsers-rust.js +28 -22
- package/lib/ecosystems/parsers-terraform.js +1573 -19
- package/lib/ecosystems/pythonutils.js +102 -6
- package/lib/ecosystems/remote/huggingface.js +3 -0
- package/lib/ecosystems/rubyutils.js +1492 -182
- package/lib/ecosystems/rusi.js +54 -10
- package/lib/ecosystems/sbtutils.js +243 -187
- package/lib/ecosystems/scalacliutils.js +342 -0
- package/lib/ecosystems/scalasem.js +2618 -0
- package/lib/ecosystems/terraformRegistry.js +288 -0
- package/lib/ecosystems/utils.js +2 -0
- package/lib/ecosystems/vendoredCode.js +156 -0
- package/lib/evinser/evinser.js +1008 -191
- package/lib/evinser/swiftsem.js +1914 -302
- package/lib/helpers/agenticToolutils.js +2 -2
- package/lib/helpers/bomSigner.js +1101 -222
- package/lib/inventory/aiCollector.js +4 -1
- package/lib/inventory/analyzer.js +110 -127
- package/lib/inventory/atomUtils.js +703 -43
- package/lib/inventory/auditCategories.js +7 -0
- package/lib/inventory/buildToolRateLimit.js +144 -0
- package/lib/inventory/cacheCommands.js +2 -1
- package/lib/inventory/cdxrs.js +103 -12
- package/lib/inventory/cmakeBuildDirs.js +254 -0
- package/lib/inventory/deps.js +501 -124
- package/lib/inventory/depsUtils.js +183 -11
- package/lib/inventory/display.js +4 -5
- package/lib/inventory/dosai.js +798 -57
- package/lib/inventory/dosaiParsers.js +310 -15
- package/lib/inventory/dynamic.js +90 -6
- package/lib/inventory/evidenceUtils.js +166 -113
- package/lib/inventory/fetchBatch.js +690 -55
- package/lib/inventory/fetchDiskCache.js +597 -0
- package/lib/inventory/forgeEnricher.js +14 -5
- package/lib/inventory/jvmLocalRepos.js +917 -0
- package/lib/inventory/mcpConfigParser.js +2 -3
- package/lib/inventory/parentSelection.js +146 -0
- package/lib/inventory/protobom.js +8 -1
- package/lib/inventory/purl.js +152 -3
- package/lib/inventory/rustFormulationParser.js +3 -4
- package/lib/inventory/sbomDocument.js +2 -70
- package/lib/inventory/scalaCoords.js +153 -0
- package/lib/inventory/source.js +45 -27
- package/lib/inventory/spdx.js +101 -0
- package/lib/inventory/traceRunner.js +295 -25
- package/lib/inventory/tracedCrypto.js +294 -0
- package/lib/managers/binary.js +115 -24
- package/lib/managers/docker.js +467 -46
- package/lib/managers/oci.js +63 -3
- package/lib/parsers/cmakeCache.js +69 -0
- package/lib/parsers/cmakeLists.js +466 -0
- package/lib/parsers/cmakePresets.js +400 -0
- package/lib/parsers/compileCommands.js +557 -0
- package/lib/parsers/largeJson.js +454 -0
- package/lib/parsers/npmrc.js +19 -1
- package/lib/parsers/strictJson.js +322 -0
- package/lib/parsers/terraformConfig.js +1073 -0
- package/lib/parsers/terraformSource.js +652 -0
- package/lib/server/server.js +23 -0
- package/lib/stages/postgen/introspection/markers.js +1 -1
- package/lib/stages/postgen/postgen.js +83 -16
- package/lib/stages/postgen/specVersionCompat.js +32 -0
- package/lib/validator/bomValidator.js +6 -16
- package/lib/validator/index.js +64 -11
- package/lib/validator/reporters/console.js +3 -0
- package/lib/validator/reporters/json.js +2 -0
- package/lib/validator/reporters/sarif.js +7 -0
- package/package.json +23 -23
- package/types/lib/audit/index.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.map +1 -1
- package/types/lib/cli/jsBom.d.ts.map +1 -1
- package/types/lib/cli/jvmBom.d.ts +24 -1
- package/types/lib/cli/jvmBom.d.ts.map +1 -1
- package/types/lib/cli/managedBom.d.ts +7 -4
- package/types/lib/cli/managedBom.d.ts.map +1 -1
- package/types/lib/cli/nativeBom.d.ts +3 -1
- 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 +9 -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/httpClient.d.ts +13 -8
- package/types/lib/core/httpClient.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/pluginRun.d.ts +97 -0
- package/types/lib/core/pluginRun.d.ts.map +1 -0
- package/types/lib/core/processTree.d.ts +36 -0
- package/types/lib/core/processTree.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/runState.d.ts +29 -0
- package/types/lib/core/runState.d.ts.map +1 -0
- package/types/lib/core/toml.d.ts +20 -0
- package/types/lib/core/toml.d.ts.map +1 -0
- package/types/lib/ecosystems/asarutils.d.ts.map +1 -1
- 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 +12 -0
- package/types/lib/ecosystems/cargoCache.d.ts.map +1 -1
- 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 +28 -3
- package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -1
- package/types/lib/ecosystems/cppBuildContext.d.ts +55 -0
- package/types/lib/ecosystems/cppBuildContext.d.ts.map +1 -0
- package/types/lib/ecosystems/cppEvidence.d.ts +17 -1
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -1
- package/types/lib/ecosystems/cppIncludeResolver.d.ts +92 -0
- package/types/lib/ecosystems/cppIncludeResolver.d.ts.map +1 -0
- package/types/lib/ecosystems/denoutils.d.ts +9 -3
- package/types/lib/ecosystems/denoutils.d.ts.map +1 -1
- package/types/lib/ecosystems/ecosystems.d.ts +62 -13
- 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 +70 -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 +13 -0
- package/types/lib/ecosystems/kosi.d.ts.map +1 -1
- package/types/lib/ecosystems/npmutils.d.ts +57 -0
- package/types/lib/ecosystems/npmutils.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-dotnet.d.ts +118 -4
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-elm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-go.d.ts +54 -2
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-js.d.ts +16 -5
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-julia.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-jvm.d.ts +46 -1
- package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-misc.d.ts +70 -4
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-python.d.ts +53 -3
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-terraform.d.ts +38 -21
- package/types/lib/ecosystems/parsers-terraform.d.ts.map +1 -1
- package/types/lib/ecosystems/pythonutils.d.ts +27 -2
- package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
- package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -1
- package/types/lib/ecosystems/rubyutils.d.ts +164 -3
- 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/ecosystems/sbtutils.d.ts +88 -2
- package/types/lib/ecosystems/sbtutils.d.ts.map +1 -1
- package/types/lib/ecosystems/scalacliutils.d.ts +56 -0
- package/types/lib/ecosystems/scalacliutils.d.ts.map +1 -0
- package/types/lib/ecosystems/scalasem.d.ts +311 -0
- package/types/lib/ecosystems/scalasem.d.ts.map +1 -0
- package/types/lib/ecosystems/terraformRegistry.d.ts +9 -0
- package/types/lib/ecosystems/terraformRegistry.d.ts.map +1 -0
- package/types/lib/ecosystems/utils.d.ts +2 -2
- package/types/lib/ecosystems/utils.d.ts.map +1 -1
- package/types/lib/ecosystems/vendoredCode.d.ts +32 -0
- package/types/lib/ecosystems/vendoredCode.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +132 -15
- 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/bomSigner.d.ts +182 -13
- package/types/lib/helpers/bomSigner.d.ts.map +1 -1
- package/types/lib/inventory/aiCollector.d.ts.map +1 -1
- package/types/lib/inventory/analyzer.d.ts.map +1 -1
- package/types/lib/inventory/atomUtils.d.ts +219 -5
- package/types/lib/inventory/atomUtils.d.ts.map +1 -1
- package/types/lib/inventory/auditCategories.d.ts +3 -0
- package/types/lib/inventory/auditCategories.d.ts.map +1 -1
- package/types/lib/inventory/buildToolRateLimit.d.ts +38 -0
- package/types/lib/inventory/buildToolRateLimit.d.ts.map +1 -0
- package/types/lib/inventory/cacheCommands.d.ts +2 -1
- package/types/lib/inventory/cacheCommands.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/cmakeBuildDirs.d.ts +58 -0
- package/types/lib/inventory/cmakeBuildDirs.d.ts.map +1 -0
- package/types/lib/inventory/deps.d.ts +59 -1
- package/types/lib/inventory/deps.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 +121 -9
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/dosaiParsers.d.ts +53 -7
- package/types/lib/inventory/dosaiParsers.d.ts.map +1 -1
- package/types/lib/inventory/dynamic.d.ts +10 -0
- package/types/lib/inventory/dynamic.d.ts.map +1 -1
- package/types/lib/inventory/evidenceUtils.d.ts +19 -4
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
- package/types/lib/inventory/fetchBatch.d.ts +83 -14
- package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
- package/types/lib/inventory/fetchDiskCache.d.ts +169 -0
- package/types/lib/inventory/fetchDiskCache.d.ts.map +1 -0
- package/types/lib/inventory/forgeEnricher.d.ts.map +1 -1
- package/types/lib/inventory/jvmLocalRepos.d.ts +178 -0
- package/types/lib/inventory/jvmLocalRepos.d.ts.map +1 -0
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/parentSelection.d.ts +34 -0
- package/types/lib/inventory/parentSelection.d.ts.map +1 -0
- package/types/lib/inventory/plugins.d.ts.map +1 -1
- package/types/lib/inventory/protobom.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/rustFormulationParser.d.ts.map +1 -1
- package/types/lib/inventory/sbomDocument.d.ts.map +1 -1
- package/types/lib/inventory/scalaCoords.d.ts +80 -0
- package/types/lib/inventory/scalaCoords.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/inventory/spdx.d.ts +9 -0
- package/types/lib/inventory/spdx.d.ts.map +1 -1
- package/types/lib/inventory/traceRunner.d.ts +59 -1
- package/types/lib/inventory/traceRunner.d.ts.map +1 -1
- package/types/lib/inventory/tracedCrypto.d.ts +42 -0
- package/types/lib/inventory/tracedCrypto.d.ts.map +1 -0
- 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 +17 -1
- package/types/lib/managers/oci.d.ts.map +1 -1
- package/types/lib/parsers/cmakeCache.d.ts +16 -0
- package/types/lib/parsers/cmakeCache.d.ts.map +1 -1
- package/types/lib/parsers/cmakeLists.d.ts +77 -0
- package/types/lib/parsers/cmakeLists.d.ts.map +1 -0
- package/types/lib/parsers/cmakePresets.d.ts +78 -0
- package/types/lib/parsers/cmakePresets.d.ts.map +1 -0
- package/types/lib/parsers/compileCommands.d.ts +115 -0
- package/types/lib/parsers/compileCommands.d.ts.map +1 -0
- 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/strictJson.d.ts +46 -0
- package/types/lib/parsers/strictJson.d.ts.map +1 -0
- package/types/lib/parsers/terraformConfig.d.ts +70 -0
- package/types/lib/parsers/terraformConfig.d.ts.map +1 -0
- package/types/lib/parsers/terraformSource.d.ts +66 -0
- package/types/lib/parsers/terraformSource.d.ts.map +1 -0
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
- package/types/lib/validator/index.d.ts +18 -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
- package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +0 -462
package/bin/cdxgen.js
CHANGED
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
isDeferredFailOnError,
|
|
35
35
|
} from "../lib/core/deferredExit.js";
|
|
36
36
|
import { TRACE_MODE, thoughtEnd, thoughtLog } from "../lib/core/logger.js";
|
|
37
|
+
import { resolveSourcePathArgument } from "../lib/core/pluginRun.js";
|
|
37
38
|
import {
|
|
38
39
|
PROJECT_CONFIG_FILENAMES,
|
|
39
40
|
sanitizeProjectConfig,
|
|
@@ -72,7 +73,11 @@ import {
|
|
|
72
73
|
setDryRunMode,
|
|
73
74
|
shouldRunPredictiveBomAudit,
|
|
74
75
|
} from "../lib/ecosystems/utils.js";
|
|
75
|
-
import {
|
|
76
|
+
import {
|
|
77
|
+
generateSigningKeyPair,
|
|
78
|
+
signBom,
|
|
79
|
+
verifyBom,
|
|
80
|
+
} from "../lib/helpers/bomSigner.js";
|
|
76
81
|
import {
|
|
77
82
|
createOutputPlan,
|
|
78
83
|
getOutputDirectory,
|
|
@@ -81,7 +86,6 @@ import {
|
|
|
81
86
|
DEFAULT_CDX_SPEC_VERSION,
|
|
82
87
|
getSupportedCycloneDxComponentTypes,
|
|
83
88
|
isCycloneDxBom,
|
|
84
|
-
isCycloneDxComponentTypeEnabled,
|
|
85
89
|
normalizeCycloneDxComponentTypeFilter,
|
|
86
90
|
toCycloneDxSpecVersionString,
|
|
87
91
|
} from "../lib/inventory/bomUtils.js";
|
|
@@ -164,6 +168,11 @@ for (const configPattern of PROJECT_CONFIG_FILENAMES) {
|
|
|
164
168
|
`Config file '${configPath}' sets '${foundKey}'. Verify this is intentional.`,
|
|
165
169
|
);
|
|
166
170
|
}
|
|
171
|
+
for (const propertyName of sanitized.reservedProperties) {
|
|
172
|
+
console.warn(
|
|
173
|
+
`\x1b[1;35mConfig file '${configPath}' sets the metadata property '${propertyName}', whose namespace cdxgen reserves for its own findings. Ignoring it. Pass the property with --metadata-property if this is intentional.\x1b[0m`,
|
|
174
|
+
);
|
|
175
|
+
}
|
|
167
176
|
} catch (_e) {
|
|
168
177
|
console.log("Invalid config file", configPath);
|
|
169
178
|
}
|
|
@@ -252,6 +261,16 @@ const args = _yargs
|
|
|
252
261
|
description:
|
|
253
262
|
"Perform deep searches for components. Useful while scanning C/C++ apps, live OS and oci images.",
|
|
254
263
|
})
|
|
264
|
+
.option("cmake-cache", {
|
|
265
|
+
type: "string",
|
|
266
|
+
description:
|
|
267
|
+
"Path to the CMakeCache.txt of a configured C/C++ build. Overrides the lookup in the build directories of the CMake presets, build*/, out/, builddir/ and cmake-build-*/.",
|
|
268
|
+
})
|
|
269
|
+
.option("compile-commands", {
|
|
270
|
+
type: "string",
|
|
271
|
+
description:
|
|
272
|
+
"Path to the compile_commands.json of a C/C++ build, or a directory holding one. atom then parses each file with its build's include paths, macros and language. Overrides the lookup in the project root and its build directories (those of the CMake presets, build*/, out/, builddir/, cmake-build-*/), which is skipped in secure mode.",
|
|
273
|
+
})
|
|
255
274
|
.option("git-branch", {
|
|
256
275
|
description: "Git branch to clone when the source is a git URL or purl",
|
|
257
276
|
type: "string",
|
|
@@ -399,7 +418,7 @@ const args = _yargs
|
|
|
399
418
|
.option("generate-key-and-sign", {
|
|
400
419
|
type: "boolean",
|
|
401
420
|
description:
|
|
402
|
-
"Generate
|
|
421
|
+
"Generate a public/private key pair for SBOM_SIGN_ALGORITHM (RS512 by default) and then sign the generated SBOM using the JSON Signature Format (JSF).",
|
|
403
422
|
})
|
|
404
423
|
.option("server", {
|
|
405
424
|
type: "boolean",
|
|
@@ -438,6 +457,23 @@ const args = _yargs
|
|
|
438
457
|
default: false,
|
|
439
458
|
description: "Generate SBOM with evidence for supported languages.",
|
|
440
459
|
})
|
|
460
|
+
.option("scalasem", {
|
|
461
|
+
type: "boolean",
|
|
462
|
+
default: true,
|
|
463
|
+
description:
|
|
464
|
+
"Run the Scala semantic analyzer for the evidence of Scala projects. Use --no-scalasem to skip it.",
|
|
465
|
+
})
|
|
466
|
+
.option("scalasem-command", {
|
|
467
|
+
type: "string",
|
|
468
|
+
description:
|
|
469
|
+
"Use a specific scalasem script for the Scala evidence. Defaults to SCALASEM_CMD.",
|
|
470
|
+
})
|
|
471
|
+
.option("scalasem-include-tests", {
|
|
472
|
+
type: "boolean",
|
|
473
|
+
default: false,
|
|
474
|
+
description:
|
|
475
|
+
"Include test sources in the Scala evidence, tagged with their usage scope.",
|
|
476
|
+
})
|
|
441
477
|
.option("deps-slices-file", {
|
|
442
478
|
description: "Path for the parsedeps slice file created by atom.",
|
|
443
479
|
default: "deps.slices.json",
|
|
@@ -565,6 +601,11 @@ const args = _yargs
|
|
|
565
601
|
default: false,
|
|
566
602
|
description: "Disable default ignore lists during scanning.",
|
|
567
603
|
})
|
|
604
|
+
.option("caxa-app-dir", {
|
|
605
|
+
type: "string",
|
|
606
|
+
description:
|
|
607
|
+
"Directory of the app a caxa binary extracts. With -t caxa, also records the native tools, the vendored PHP, Ruby and Java packages, and the npm integrity hashes found there.",
|
|
608
|
+
})
|
|
568
609
|
.option("export-proto", {
|
|
569
610
|
type: "boolean",
|
|
570
611
|
default: false,
|
|
@@ -605,6 +646,12 @@ const args = _yargs
|
|
|
605
646
|
default: false,
|
|
606
647
|
description: "Synthesize custom LicenseRef IDs for unresolved licenses.",
|
|
607
648
|
})
|
|
649
|
+
.option("metadata-property", {
|
|
650
|
+
description:
|
|
651
|
+
"Custom property to add to the BOM metadata, as name=value. Repeat the flag for several properties. Combined with the properties of the CDXGEN_METADATA_PROPERTIES environment variable and of a config file.",
|
|
652
|
+
nargs: 1,
|
|
653
|
+
type: "array",
|
|
654
|
+
})
|
|
608
655
|
.option("standard", {
|
|
609
656
|
description:
|
|
610
657
|
"The list of standards which may consist of regulations, industry or organizational-specific standards, maturity models, best practices, or any other requirements which can be evaluated against or attested to.",
|
|
@@ -864,7 +911,7 @@ const args = _yargs
|
|
|
864
911
|
type: "boolean",
|
|
865
912
|
default: true,
|
|
866
913
|
description:
|
|
867
|
-
"Use the on-disk metadata cache for registry lookups. Pass --no-cache to bypass it for this run.",
|
|
914
|
+
"Use the on-disk metadata cache for registry lookups. Pass --no-cache to bypass it for this run; answers are still remembered within the run.",
|
|
868
915
|
})
|
|
869
916
|
.option("cache-ttl", {
|
|
870
917
|
type: "number",
|
|
@@ -984,9 +1031,24 @@ if (!readEnvironmentVariable("NODE_USE_SYSTEM_CA")) {
|
|
|
984
1031
|
process.env.NODE_USE_SYSTEM_CA = "1";
|
|
985
1032
|
}
|
|
986
1033
|
|
|
987
|
-
|
|
1034
|
+
let filePath = args._[0] || process.cwd();
|
|
988
1035
|
const sourceInputIsRemoteOrPurl =
|
|
989
1036
|
maybeRemotePath(filePath) || maybePurlSource(filePath);
|
|
1037
|
+
// Resolve the source argument once, before anything uses it. With the working
|
|
1038
|
+
// directory already set to the project and the argument relative to a
|
|
1039
|
+
// repository root (depscan's launch shape), every later resolve would produce
|
|
1040
|
+
// <project>/<argument>, a directory that does not exist: the BOM came out
|
|
1041
|
+
// empty and the plugins analyzed nothing, while the run still exited 0.
|
|
1042
|
+
if (!sourceInputIsRemoteOrPurl && args._?.[0]) {
|
|
1043
|
+
const sourceResolution = resolveSourcePathArgument(filePath);
|
|
1044
|
+
if (sourceResolution.rewritten) {
|
|
1045
|
+
console.warn(
|
|
1046
|
+
`Source path '${filePath}' does not exist relative to the working directory, which is itself the directory it names; using '${sourceResolution.path}'.`,
|
|
1047
|
+
);
|
|
1048
|
+
filePath = sourceResolution.path;
|
|
1049
|
+
args._[0] = filePath;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
990
1052
|
if (!args.projectName) {
|
|
991
1053
|
if (filePath !== ".") {
|
|
992
1054
|
args.projectName = basename(filePath);
|
|
@@ -1047,6 +1109,7 @@ const { options, warnings: phase3Warnings } = buildOptionsFromArgs(args, {
|
|
|
1047
1109
|
userSetSpecVersion,
|
|
1048
1110
|
isDryRun,
|
|
1049
1111
|
isSecureMode,
|
|
1112
|
+
projectConfig: config,
|
|
1050
1113
|
});
|
|
1051
1114
|
// Exit status reserved for the introspection CI gate: the BOM was generated
|
|
1052
1115
|
// and written, but its introspection score missed the configured threshold.
|
|
@@ -1410,6 +1473,8 @@ const checkPermissions = (filePath, options) => {
|
|
|
1410
1473
|
return true;
|
|
1411
1474
|
};
|
|
1412
1475
|
|
|
1476
|
+
let warnedAboutSigningAlgorithm = false;
|
|
1477
|
+
|
|
1413
1478
|
const needsBomSigning = ({ generateKeyAndSign }) =>
|
|
1414
1479
|
generateKeyAndSign ||
|
|
1415
1480
|
(() => {
|
|
@@ -1427,11 +1492,19 @@ const needsBomSigning = ({ generateKeyAndSign }) =>
|
|
|
1427
1492
|
sensitive: true,
|
|
1428
1493
|
},
|
|
1429
1494
|
);
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1495
|
+
const keyConfigured = Boolean(
|
|
1496
|
+
sbomSignPrivateKey || sbomSignPrivateKeyBase64,
|
|
1497
|
+
);
|
|
1498
|
+
if (keyConfigured && !sbomSignAlgorithm && !warnedAboutSigningAlgorithm) {
|
|
1499
|
+
warnedAboutSigningAlgorithm = true;
|
|
1500
|
+
console.warn(
|
|
1501
|
+
"SBOM_SIGN_PRIVATE_KEY is set without SBOM_SIGN_ALGORITHM, so the BOM is not signed. Set SBOM_SIGN_ALGORITHM (for example RS512) to sign it, or SBOM_SIGN_ALGORITHM=none to silence this warning.",
|
|
1502
|
+
);
|
|
1503
|
+
}
|
|
1504
|
+
// A configured key file that is missing counts as a signing request, so
|
|
1505
|
+
// that signing fails loudly instead of being skipped.
|
|
1506
|
+
return Boolean(
|
|
1507
|
+
sbomSignAlgorithm && sbomSignAlgorithm !== "none" && keyConfigured,
|
|
1435
1508
|
);
|
|
1436
1509
|
})();
|
|
1437
1510
|
|
|
@@ -1440,28 +1513,20 @@ const stringifyJson = (jsonPayload, jsonPretty) =>
|
|
|
1440
1513
|
? jsonPayload
|
|
1441
1514
|
: JSON.stringify(jsonPayload, null, jsonPretty ? 2 : null);
|
|
1442
1515
|
|
|
1443
|
-
const
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
recordActivity({
|
|
1458
|
-
kind: "sign",
|
|
1459
|
-
reason: "Dry run mode skips BOM signing and key generation.",
|
|
1460
|
-
status: "blocked",
|
|
1461
|
-
target: jsonFile,
|
|
1462
|
-
});
|
|
1463
|
-
return jsonPayload;
|
|
1464
|
-
}
|
|
1516
|
+
const SIGNING_HINT =
|
|
1517
|
+
"Check that the private key is in PEM format and that SBOM_SIGN_ALGORITHM matches its key type.";
|
|
1518
|
+
|
|
1519
|
+
/**
|
|
1520
|
+
* Signs a CycloneDX payload with the configured or generated key.
|
|
1521
|
+
*
|
|
1522
|
+
* @param {string} jsonPayload Serialized CycloneDX BOM
|
|
1523
|
+
* @param {string|undefined} keyDir Directory for --generate-key-and-sign keys
|
|
1524
|
+
* @param {string} target Output the signed BOM is written to (for the activity log)
|
|
1525
|
+
* @param {Object} options CLI options
|
|
1526
|
+
* @returns {Object} Signed BOM
|
|
1527
|
+
* @throws {Error} When signing was requested but cannot be completed
|
|
1528
|
+
*/
|
|
1529
|
+
const signCycloneDxPayload = (jsonPayload, keyDir, target, options) => {
|
|
1465
1530
|
const sbomSignAlgorithm = readEnvironmentVariable("SBOM_SIGN_ALGORITHM");
|
|
1466
1531
|
const sbomSignPrivateKey = readEnvironmentVariable("SBOM_SIGN_PRIVATE_KEY", {
|
|
1467
1532
|
sensitive: true,
|
|
@@ -1476,29 +1541,20 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
1476
1541
|
const sbomSignPublicKeyBase64 = readEnvironmentVariable(
|
|
1477
1542
|
"SBOM_SIGN_PUBLIC_KEY_BASE64",
|
|
1478
1543
|
);
|
|
1479
|
-
|
|
1480
|
-
if (alg.includes("none")) {
|
|
1481
|
-
alg = "RS512";
|
|
1482
|
-
}
|
|
1544
|
+
const alg = sbomSignAlgorithm || "RS512";
|
|
1483
1545
|
let privateKeyToUse;
|
|
1484
1546
|
let jwkPublicKey;
|
|
1485
1547
|
let publicKeyFile;
|
|
1486
1548
|
if (options.generateKeyAndSign) {
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
},
|
|
1497
|
-
privateKeyEncoding: {
|
|
1498
|
-
type: "pkcs8",
|
|
1499
|
-
format: "pem",
|
|
1500
|
-
},
|
|
1501
|
-
});
|
|
1549
|
+
if (!keyDir) {
|
|
1550
|
+
throw new Error(
|
|
1551
|
+
"--generate-key-and-sign needs a file output (-o) to write the generated keys next to.",
|
|
1552
|
+
);
|
|
1553
|
+
}
|
|
1554
|
+
publicKeyFile = join(keyDir, "public.key");
|
|
1555
|
+
const privateKeyFile = join(keyDir, "private.key");
|
|
1556
|
+
const privateKeyB64File = join(keyDir, "private.key.base64");
|
|
1557
|
+
const { privateKey, publicKey } = generateSigningKeyPair(alg);
|
|
1502
1558
|
safeWriteSync(publicKeyFile, publicKey);
|
|
1503
1559
|
safeWriteSync(privateKeyFile, privateKey);
|
|
1504
1560
|
safeWriteSync(
|
|
@@ -1515,69 +1571,129 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
1515
1571
|
jwkPublicKey = crypto.createPublicKey(publicKey).export({ format: "jwk" });
|
|
1516
1572
|
} else {
|
|
1517
1573
|
if (sbomSignPrivateKey) {
|
|
1574
|
+
if (!safeExistsSync(sbomSignPrivateKey)) {
|
|
1575
|
+
throw new Error(
|
|
1576
|
+
`The SBOM_SIGN_PRIVATE_KEY file '${sbomSignPrivateKey}' was not found.`,
|
|
1577
|
+
);
|
|
1578
|
+
}
|
|
1518
1579
|
recordSensitiveFileRead(sbomSignPrivateKey, {
|
|
1519
1580
|
label: "SBOM signing private key",
|
|
1520
1581
|
});
|
|
1521
|
-
privateKeyToUse = fs.readFileSync(sbomSignPrivateKey
|
|
1582
|
+
privateKeyToUse = fs.readFileSync(sbomSignPrivateKey);
|
|
1522
1583
|
} else if (sbomSignPrivateKeyBase64) {
|
|
1523
|
-
privateKeyToUse = Buffer.from(
|
|
1524
|
-
sbomSignPrivateKeyBase64,
|
|
1525
|
-
"base64",
|
|
1526
|
-
).toString("utf8");
|
|
1584
|
+
privateKeyToUse = Buffer.from(sbomSignPrivateKeyBase64, "base64");
|
|
1527
1585
|
}
|
|
1528
1586
|
if (sbomSignPublicKey && safeExistsSync(sbomSignPublicKey)) {
|
|
1529
1587
|
jwkPublicKey = crypto
|
|
1530
1588
|
.createPublicKey(fs.readFileSync(sbomSignPublicKey, "utf8"))
|
|
1531
1589
|
.export({ format: "jwk" });
|
|
1532
1590
|
} else if (sbomSignPublicKeyBase64) {
|
|
1533
|
-
jwkPublicKey =
|
|
1534
|
-
"
|
|
1591
|
+
jwkPublicKey = crypto
|
|
1592
|
+
.createPublicKey(Buffer.from(sbomSignPublicKeyBase64, "base64"))
|
|
1593
|
+
.export({ format: "jwk" });
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
thoughtLog(`Signing the BOM for "${target}".`);
|
|
1597
|
+
const signedBom = signBom(JSON.parse(jsonPayload), {
|
|
1598
|
+
privateKey: privateKeyToUse,
|
|
1599
|
+
algorithm: alg,
|
|
1600
|
+
publicKeyJwk: jwkPublicKey,
|
|
1601
|
+
mode: readEnvironmentVariable("SBOM_SIGN_MODE") || "replace",
|
|
1602
|
+
signComponents: true,
|
|
1603
|
+
signServices: true,
|
|
1604
|
+
signAnnotations: true,
|
|
1605
|
+
});
|
|
1606
|
+
if (publicKeyFile) {
|
|
1607
|
+
if (!verifyBom(signedBom, fs.readFileSync(publicKeyFile, "utf8"))) {
|
|
1608
|
+
throw new Error(
|
|
1609
|
+
`The new signature does not verify with ${publicKeyFile}.`,
|
|
1535
1610
|
);
|
|
1536
1611
|
}
|
|
1612
|
+
console.log(
|
|
1613
|
+
"SBOM signature is verifiable natively with the public key and the algorithm",
|
|
1614
|
+
publicKeyFile,
|
|
1615
|
+
alg,
|
|
1616
|
+
);
|
|
1617
|
+
}
|
|
1618
|
+
recordActivity({
|
|
1619
|
+
kind: "sign",
|
|
1620
|
+
status: "completed",
|
|
1621
|
+
target,
|
|
1622
|
+
});
|
|
1623
|
+
return signedBom;
|
|
1624
|
+
};
|
|
1625
|
+
|
|
1626
|
+
/**
|
|
1627
|
+
* Signs the BOM for an output when signing is configured. A failure is
|
|
1628
|
+
* recorded and returned so that the caller can stop with a non-zero exit
|
|
1629
|
+
* instead of publishing an unsigned BOM.
|
|
1630
|
+
*
|
|
1631
|
+
* @returns {{ bomJson: Object, jsonPayload: string, signingError?: Error }}
|
|
1632
|
+
*/
|
|
1633
|
+
const signForOutput = (bomJson, jsonPayload, keyDir, target, options) => {
|
|
1634
|
+
if (!jsonPayload || !needsBomSigning(options)) {
|
|
1635
|
+
return { bomJson, jsonPayload };
|
|
1636
|
+
}
|
|
1637
|
+
if (isDryRun) {
|
|
1638
|
+
recordActivity({
|
|
1639
|
+
kind: "sign",
|
|
1640
|
+
reason: "Dry run mode skips BOM signing and key generation.",
|
|
1641
|
+
status: "blocked",
|
|
1642
|
+
target,
|
|
1643
|
+
});
|
|
1644
|
+
return { bomJson, jsonPayload };
|
|
1537
1645
|
}
|
|
1538
1646
|
try {
|
|
1539
|
-
const
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1647
|
+
const signedBom = signCycloneDxPayload(
|
|
1648
|
+
jsonPayload,
|
|
1649
|
+
keyDir,
|
|
1650
|
+
target,
|
|
1651
|
+
options,
|
|
1652
|
+
);
|
|
1653
|
+
return {
|
|
1654
|
+
bomJson: signedBom,
|
|
1655
|
+
jsonPayload: JSON.stringify(
|
|
1656
|
+
signedBom,
|
|
1657
|
+
null,
|
|
1658
|
+
options.jsonPretty ? 2 : null,
|
|
1659
|
+
),
|
|
1548
1660
|
};
|
|
1549
|
-
|
|
1661
|
+
} catch (err) {
|
|
1550
1662
|
recordActivity({
|
|
1551
1663
|
kind: "sign",
|
|
1552
|
-
|
|
1553
|
-
|
|
1664
|
+
reason: err.message,
|
|
1665
|
+
status: "failed",
|
|
1666
|
+
target,
|
|
1554
1667
|
});
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1668
|
+
return { bomJson, jsonPayload, signingError: err };
|
|
1669
|
+
}
|
|
1670
|
+
};
|
|
1671
|
+
|
|
1672
|
+
const reportSigningFailure = (signingError, target) => {
|
|
1673
|
+
console.error(`SBOM signing was unsuccessful: ${signingError.message}`);
|
|
1674
|
+
console.error(SIGNING_HINT);
|
|
1675
|
+
if (target !== "stdout") {
|
|
1676
|
+
console.error(`The BOM at '${target}' was written without a signature.`);
|
|
1677
|
+
}
|
|
1678
|
+
};
|
|
1679
|
+
|
|
1680
|
+
const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
1681
|
+
const result = signForOutput(
|
|
1682
|
+
bomJson,
|
|
1683
|
+
stringifyJson(bomJson, options.jsonPretty),
|
|
1684
|
+
dirname(jsonFile),
|
|
1685
|
+
jsonFile,
|
|
1686
|
+
options,
|
|
1687
|
+
);
|
|
1688
|
+
safeWriteSync(jsonFile, result.jsonPayload);
|
|
1689
|
+
if (jsonFile.endsWith("bom.json")) {
|
|
1690
|
+
thoughtLog(
|
|
1691
|
+
`Let's save the file to "${jsonFile}". Should I suggest the '.cdx.json' file extension for better semantics?`,
|
|
1578
1692
|
);
|
|
1693
|
+
} else {
|
|
1694
|
+
thoughtLog(`Let's save the file to "${jsonFile}".`);
|
|
1579
1695
|
}
|
|
1580
|
-
return
|
|
1696
|
+
return result;
|
|
1581
1697
|
};
|
|
1582
1698
|
|
|
1583
1699
|
/**
|
|
@@ -2054,46 +2170,61 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2054
2170
|
sourcePath: filePath,
|
|
2055
2171
|
});
|
|
2056
2172
|
const evinserModule = await import("../lib/evinser/evinser.js");
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
language: options.projectType,
|
|
2063
|
-
skipMavenCollector: false,
|
|
2064
|
-
force: false,
|
|
2065
|
-
withReachables: options.deep,
|
|
2066
|
-
usagesSlicesFile: options.usagesSlicesFile,
|
|
2067
|
-
dataFlowSlicesFile: options.dataFlowSlicesFile,
|
|
2068
|
-
reachablesSlicesFile: options.reachablesSlicesFile,
|
|
2069
|
-
semanticsSlicesFile: options.semanticsSlicesFile,
|
|
2070
|
-
openapiSpecFile: options.openapiSpecFile,
|
|
2071
|
-
componentType: options.componentType,
|
|
2072
|
-
includeCrypto:
|
|
2073
|
-
options.includeCrypto &&
|
|
2074
|
-
isCycloneDxComponentTypeEnabled("cryptographic-asset", options),
|
|
2075
|
-
specVersion: options.specVersion,
|
|
2076
|
-
profile: options.profile,
|
|
2077
|
-
jsonPretty: options.jsonPretty,
|
|
2078
|
-
};
|
|
2079
|
-
const dbObjMap = await evinserModule.prepareDB(evinseOptions);
|
|
2080
|
-
if (dbObjMap) {
|
|
2081
|
-
const sliceArtefacts = await evinserModule.analyzeProject(
|
|
2082
|
-
dbObjMap,
|
|
2083
|
-
evinseOptions,
|
|
2173
|
+
if (!options.projectType) {
|
|
2174
|
+
const evidenceLanguage = evinserModule.defaultEvidenceLanguage(
|
|
2175
|
+
filePath,
|
|
2176
|
+
bomNSData?.bomJson,
|
|
2177
|
+
options,
|
|
2084
2178
|
);
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2179
|
+
if (evidenceLanguage) {
|
|
2180
|
+
options.projectType = [evidenceLanguage];
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
if (!options.projectType) {
|
|
2184
|
+
console.log(
|
|
2185
|
+
"Skipping the evidence analysis since the BOM lists no package in a language it supports. Pass -t to choose the language.",
|
|
2088
2186
|
);
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2187
|
+
if (bomNSData) {
|
|
2188
|
+
bomNSData.bomJson = applyEvidenceBasedFilter(
|
|
2189
|
+
bomNSData.bomJson,
|
|
2190
|
+
options,
|
|
2191
|
+
);
|
|
2192
|
+
}
|
|
2193
|
+
} else {
|
|
2194
|
+
const evinseOptions = evinserModule.buildEvinseOptions(
|
|
2195
|
+
options,
|
|
2196
|
+
args,
|
|
2197
|
+
internalCycloneDxInputPath || options.output,
|
|
2198
|
+
);
|
|
2199
|
+
try {
|
|
2200
|
+
const dbObjMap = await evinserModule.prepareDB(evinseOptions);
|
|
2201
|
+
if (dbObjMap) {
|
|
2202
|
+
const sliceArtefacts = await evinserModule.analyzeProject(
|
|
2203
|
+
dbObjMap,
|
|
2204
|
+
evinseOptions,
|
|
2205
|
+
);
|
|
2206
|
+
const evinseJson = await evinserModule.createEvinseFile(
|
|
2207
|
+
sliceArtefacts,
|
|
2208
|
+
evinseOptions,
|
|
2209
|
+
);
|
|
2210
|
+
// The scope filter is deferred until here so the analyzers get to
|
|
2211
|
+
// prove that an optional dependency is actually used.
|
|
2212
|
+
bomNSData.bomJson = applyEvidenceBasedFilter(evinseJson, options);
|
|
2213
|
+
if (options.print && evinseJson) {
|
|
2214
|
+
printOccurrences(evinseJson);
|
|
2215
|
+
printCallStack(evinseJson);
|
|
2216
|
+
printReachables(sliceArtefacts);
|
|
2217
|
+
printServices(evinseJson);
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
} catch (err) {
|
|
2221
|
+
// A rusi/golem analysis failure under --fail-on-error on an
|
|
2222
|
+
// introspected run defers its exit so the BOM and the reports are
|
|
2223
|
+
// still written; the run continues here without the reachability
|
|
2224
|
+
// evidence, exactly as the deferral contract describes.
|
|
2225
|
+
if (!isDeferredFailOnError(err)) {
|
|
2226
|
+
throw err;
|
|
2227
|
+
}
|
|
2097
2228
|
}
|
|
2098
2229
|
}
|
|
2099
2230
|
}
|
|
@@ -2164,10 +2295,27 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2164
2295
|
}
|
|
2165
2296
|
if (outputIsStdout) {
|
|
2166
2297
|
if (!isDryRun && bomNSData.bomJson) {
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2298
|
+
let payload;
|
|
2299
|
+
if (outputPlan.formats.has("spdx") && bomNSData.spdxJson) {
|
|
2300
|
+
payload = stringifyJson(bomNSData.spdxJson, options.jsonPretty);
|
|
2301
|
+
} else {
|
|
2302
|
+
const result = signForOutput(
|
|
2303
|
+
bomNSData.bomJson,
|
|
2304
|
+
stringifyJson(bomNSData.bomJson, options.jsonPretty),
|
|
2305
|
+
undefined,
|
|
2306
|
+
"stdout",
|
|
2307
|
+
options,
|
|
2308
|
+
);
|
|
2309
|
+
if (result.signingError) {
|
|
2310
|
+
reportSigningFailure(result.signingError, "stdout");
|
|
2311
|
+
if (cleanup) {
|
|
2312
|
+
cleanupSourceDir(srcDir);
|
|
2313
|
+
}
|
|
2314
|
+
process.exit(1);
|
|
2315
|
+
}
|
|
2316
|
+
bomNSData.bomJson = result.bomJson;
|
|
2317
|
+
payload = result.jsonPayload;
|
|
2318
|
+
}
|
|
2171
2319
|
process.stdout.write(payload);
|
|
2172
2320
|
} else if (isDryRun) {
|
|
2173
2321
|
recordActivity({
|
|
@@ -2182,11 +2330,20 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2182
2330
|
(typeof options.output === "string" || options.output instanceof String)
|
|
2183
2331
|
) {
|
|
2184
2332
|
if (!isDryRun && outputPlan.outputs.cyclonedx && bomNSData.bomJson) {
|
|
2185
|
-
writeCycloneDxOutput(
|
|
2333
|
+
const result = writeCycloneDxOutput(
|
|
2186
2334
|
outputPlan.outputs.cyclonedx,
|
|
2187
2335
|
bomNSData.bomJson,
|
|
2188
2336
|
options,
|
|
2189
2337
|
);
|
|
2338
|
+
if (result.signingError) {
|
|
2339
|
+
reportSigningFailure(result.signingError, outputPlan.outputs.cyclonedx);
|
|
2340
|
+
if (cleanup) {
|
|
2341
|
+
cleanupSourceDir(srcDir);
|
|
2342
|
+
}
|
|
2343
|
+
process.exit(1);
|
|
2344
|
+
}
|
|
2345
|
+
// Later consumers, such as the Dependency-Track upload, get the signed BOM.
|
|
2346
|
+
bomNSData.bomJson = result.bomJson;
|
|
2190
2347
|
if (bomNSData.nsMapping && Object.keys(bomNSData.nsMapping).length) {
|
|
2191
2348
|
const nsFile = `${outputPlan.outputs.cyclonedx}.map`;
|
|
2192
2349
|
safeWriteSync(nsFile, JSON.stringify(bomNSData.nsMapping));
|
|
@@ -2217,7 +2374,22 @@ const writeCycloneDxOutput = (jsonFile, bomJson, options) => {
|
|
|
2217
2374
|
if (outputPlan.formats.has("spdx") && bomNSData?.spdxJson) {
|
|
2218
2375
|
console.log(stringifyJson(bomNSData.spdxJson, options.jsonPretty));
|
|
2219
2376
|
} else if (bomNSData.bomJson) {
|
|
2220
|
-
|
|
2377
|
+
const result = signForOutput(
|
|
2378
|
+
bomNSData.bomJson,
|
|
2379
|
+
stringifyJson(bomNSData.bomJson, options.jsonPretty),
|
|
2380
|
+
undefined,
|
|
2381
|
+
"stdout",
|
|
2382
|
+
options,
|
|
2383
|
+
);
|
|
2384
|
+
if (result.signingError) {
|
|
2385
|
+
reportSigningFailure(result.signingError, "stdout");
|
|
2386
|
+
if (cleanup) {
|
|
2387
|
+
cleanupSourceDir(srcDir);
|
|
2388
|
+
}
|
|
2389
|
+
process.exit(1);
|
|
2390
|
+
}
|
|
2391
|
+
bomNSData.bomJson = result.bomJson;
|
|
2392
|
+
console.log(result.jsonPayload);
|
|
2221
2393
|
} else {
|
|
2222
2394
|
console.log("Unable to produce BOM for", filePath);
|
|
2223
2395
|
console.log("Try running the command with -t <type> or -r argument");
|
package/bin/evinse.js
CHANGED
|
@@ -89,6 +89,11 @@ const args = yargs(hideBin(process.argv))
|
|
|
89
89
|
default: false,
|
|
90
90
|
type: "boolean",
|
|
91
91
|
})
|
|
92
|
+
.option("compile-commands", {
|
|
93
|
+
description:
|
|
94
|
+
"Path to the compile_commands.json of a C/C++ build, or a directory holding one, for atom to parse each file as its build does. Overrides the lookup in the project root and its build directories (those of the CMake presets, build*/, out/, builddir/, cmake-build-*/), which is skipped in secure mode.",
|
|
95
|
+
type: "string",
|
|
96
|
+
})
|
|
92
97
|
.option("golem-command", {
|
|
93
98
|
description: "Use a specific golem binary for Go Evinse analysis.",
|
|
94
99
|
default: readEnvironmentVariable("GOLEM_CMD"),
|
|
@@ -259,6 +264,23 @@ const args = yargs(hideBin(process.argv))
|
|
|
259
264
|
description: "Use an existing usages slices file.",
|
|
260
265
|
default: "usages.slices.json",
|
|
261
266
|
})
|
|
267
|
+
.option("scalasem-command", {
|
|
268
|
+
description:
|
|
269
|
+
"Use a specific scalasem script for Scala evidence analysis. Defaults to SCALASEM_CMD.",
|
|
270
|
+
default: readEnvironmentVariable("SCALASEM_CMD"),
|
|
271
|
+
})
|
|
272
|
+
.option("scalasem-include-tests", {
|
|
273
|
+
description:
|
|
274
|
+
"Include test sources in the Scala semantic evidence, tagged with their usage scope.",
|
|
275
|
+
default: false,
|
|
276
|
+
type: "boolean",
|
|
277
|
+
})
|
|
278
|
+
.option("scalasem", {
|
|
279
|
+
description:
|
|
280
|
+
"Run the Scala semantic analyzer for Scala projects. Use --no-scalasem to skip it and keep the plain BOM.",
|
|
281
|
+
default: true,
|
|
282
|
+
type: "boolean",
|
|
283
|
+
})
|
|
262
284
|
.option("data-flow-slices-file", {
|
|
263
285
|
description: "Use an existing data-flow slices file.",
|
|
264
286
|
default: "data-flow.slices.json",
|