@cdxgen/cdxgen 13.1.0 → 13.2.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 +8 -7
- package/bin/cdxgen.js +16 -3
- package/bin/evinse.js +2 -0
- package/data/crypto-oid.json +88 -12
- package/data/remediations.json +23 -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 +12 -0
- package/lib/cli/index.js +192 -1
- package/lib/cli/jsBom.js +59 -2
- package/lib/cli/jvmBom.js +22 -0
- package/lib/cli/managedBom.js +152 -0
- package/lib/cli/nativeBom.js +798 -1
- package/lib/core/activity.js +120 -2
- package/lib/core/env.js +39 -1
- package/lib/core/userAgent.js +151 -0
- package/lib/ecosystems/cargoCache.js +364 -0
- package/lib/ecosystems/caxa.js +13 -5
- package/lib/ecosystems/cppEvidence.js +40 -2
- package/lib/ecosystems/ecosystems.js +241 -91
- package/lib/ecosystems/golem.js +11 -1
- package/lib/ecosystems/gradleutils.js +143 -2
- package/lib/ecosystems/kosi.js +1256 -0
- package/lib/ecosystems/parsers-crystal.js +179 -0
- package/lib/ecosystems/parsers-dotnet.js +69 -39
- package/lib/ecosystems/parsers-elm.js +816 -0
- package/lib/ecosystems/parsers-gleam.js +1 -1
- package/lib/ecosystems/parsers-julia.js +268 -0
- package/lib/ecosystems/parsers-lua.js +218 -0
- package/lib/ecosystems/parsers-misc.js +172 -0
- 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 +1 -1
- package/lib/ecosystems/parsers-r.js +148 -0
- package/lib/ecosystems/parsers-rebar.js +411 -0
- package/lib/ecosystems/parsers-rust.js +932 -17
- 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/rusi.js +126 -6
- package/lib/evinser/evinser.js +111 -1
- package/lib/helpers/agenticToolutils.js +925 -0
- 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/auditCategories.js +8 -0
- package/lib/inventory/cbomutils.js +30 -0
- package/lib/inventory/cdxrs.js +7 -2
- package/lib/inventory/communityAiConfigParser.js +215 -2
- package/lib/inventory/dosai.js +77 -0
- package/lib/inventory/envcontext.js +9 -6
- package/lib/inventory/evidenceUtils.js +13 -0
- package/lib/inventory/fetchBatch.js +74 -2
- 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 +54 -88
- package/lib/inventory/protobomLoader.js +4 -0
- package/lib/inventory/rustFormulationParser.js +1 -1
- package/lib/inventory/source.js +10 -4
- package/lib/inventory/stylePackageRefs.js +41 -0
- package/lib/inventory/svelteUtils.js +524 -0
- package/lib/parsers/huggingfaceUtils.js +15 -7
- 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 +169 -1
- package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +462 -0
- package/package.json +25 -25
- package/types/lib/audit/targets.d.ts.map +1 -1
- package/types/lib/cli/bomAssembly.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/userAgent.d.ts +56 -0
- package/types/lib/core/userAgent.d.ts.map +1 -0
- 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.map +1 -1
- package/types/lib/ecosystems/cppEvidence.d.ts +1 -1
- 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/gradleutils.d.ts +20 -0
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/kosi.d.ts +73 -0
- package/types/lib/ecosystems/kosi.d.ts.map +1 -0
- 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-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 +23 -0
- 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-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/rusi.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +29 -0
- package/types/lib/evinser/evinser.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/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/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/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +23 -0
- package/types/lib/inventory/dosai.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/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/parsers/huggingfaceUtils.d.ts +8 -1
- package/types/lib/parsers/huggingfaceUtils.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/lib/cli/bomAssembly.js
CHANGED
|
@@ -1097,7 +1097,19 @@ export function addComponent(
|
|
|
1097
1097
|
component.modelCard = pkg.modelCard || undefined;
|
|
1098
1098
|
component.data = pkg.data || undefined;
|
|
1099
1099
|
}
|
|
1100
|
+
if (options.specVersion >= 1.7) {
|
|
1101
|
+
// An external component is provided by the deployment environment rather
|
|
1102
|
+
// than bundled with the product. The schema defaults it to false, so it
|
|
1103
|
+
// is only worth emitting when true.
|
|
1104
|
+
component.isExternal = pkg.isExternal ? true : undefined;
|
|
1105
|
+
}
|
|
1100
1106
|
component["type"] = determinePackageType(pkg);
|
|
1107
|
+
// `version` is optional in every spec version cdxgen emits. An empty string
|
|
1108
|
+
// is not a version, and a consumer reading one has to guess whether it means
|
|
1109
|
+
// "unknown" or "the empty release"; leaving the field out says it plainly.
|
|
1110
|
+
if (!component.version) {
|
|
1111
|
+
delete component.version;
|
|
1112
|
+
}
|
|
1101
1113
|
if (pkg["bom-ref"]) {
|
|
1102
1114
|
component["bom-ref"] = pkg["bom-ref"];
|
|
1103
1115
|
} else if (purlString) {
|
package/lib/cli/index.js
CHANGED
|
@@ -32,6 +32,11 @@ import { thoughtLog } from "../core/logger.js";
|
|
|
32
32
|
import { mapWithConcurrency } from "../core/parallel.js";
|
|
33
33
|
import { dirNameStr } from "../core/paths.js";
|
|
34
34
|
import { ui } from "../core/ui.js";
|
|
35
|
+
import { isElmProjectFile } from "../ecosystems/parsers-elm.js";
|
|
36
|
+
import {
|
|
37
|
+
isJuliaManifestFile,
|
|
38
|
+
isJuliaProjectFile,
|
|
39
|
+
} from "../ecosystems/parsers-julia.js";
|
|
35
40
|
import {
|
|
36
41
|
parseBitbucketPipelinesFile,
|
|
37
42
|
parseContainerFile,
|
|
@@ -90,6 +95,7 @@ import {
|
|
|
90
95
|
determineParentComponent,
|
|
91
96
|
} from "./bomAssembly.js";
|
|
92
97
|
import {
|
|
98
|
+
createAgenticBom,
|
|
93
99
|
createAsarBom,
|
|
94
100
|
createCaxaBom,
|
|
95
101
|
createChromeExtensionBom,
|
|
@@ -126,24 +132,36 @@ import {
|
|
|
126
132
|
createGitHubBom,
|
|
127
133
|
createHelmBom,
|
|
128
134
|
createJenkinsBom,
|
|
135
|
+
createPerlBom,
|
|
129
136
|
createPHPBom,
|
|
130
137
|
createPythonBom,
|
|
138
|
+
createRBom,
|
|
131
139
|
createRubyBom,
|
|
140
|
+
createTerraformBom,
|
|
132
141
|
} from "./managedBom.js";
|
|
133
142
|
import {
|
|
134
143
|
createCargoCacheBom,
|
|
135
144
|
createClojureBom,
|
|
136
145
|
createCocoaBom,
|
|
137
146
|
createCppBom,
|
|
147
|
+
createCrystalBom,
|
|
138
148
|
createDartBom,
|
|
139
149
|
createElixirBom,
|
|
150
|
+
createElmBom,
|
|
151
|
+
createErlangBom,
|
|
140
152
|
createGleamBom,
|
|
141
153
|
createGoBom,
|
|
142
154
|
createHaskellBom,
|
|
155
|
+
createJuliaBom,
|
|
156
|
+
createLuaBom,
|
|
157
|
+
createNimBom,
|
|
143
158
|
createNixBom,
|
|
159
|
+
createOCamlBom,
|
|
144
160
|
createRustBom,
|
|
161
|
+
createSpackBom,
|
|
145
162
|
createSwiftBom,
|
|
146
163
|
createZigBom,
|
|
164
|
+
findStackLockFiles,
|
|
147
165
|
getCargoCacheDir,
|
|
148
166
|
} from "./nativeBom.js";
|
|
149
167
|
|
|
@@ -154,22 +172,33 @@ export {
|
|
|
154
172
|
createGitHubBom,
|
|
155
173
|
createHelmBom,
|
|
156
174
|
createJenkinsBom,
|
|
175
|
+
createPerlBom,
|
|
157
176
|
createPHPBom,
|
|
158
177
|
createPixiBom,
|
|
159
178
|
createPythonBom,
|
|
179
|
+
createRBom,
|
|
160
180
|
createRubyBom,
|
|
181
|
+
createTerraformBom,
|
|
161
182
|
} from "./managedBom.js";
|
|
162
183
|
export {
|
|
163
184
|
createClojureBom,
|
|
164
185
|
createCocoaBom,
|
|
165
186
|
createCppBom,
|
|
187
|
+
createCrystalBom,
|
|
166
188
|
createDartBom,
|
|
167
189
|
createElixirBom,
|
|
190
|
+
createElmBom,
|
|
191
|
+
createErlangBom,
|
|
168
192
|
createGleamBom,
|
|
169
193
|
createGoBom,
|
|
170
194
|
createHaskellBom,
|
|
195
|
+
createJuliaBom,
|
|
196
|
+
createLuaBom,
|
|
197
|
+
createNimBom,
|
|
171
198
|
createNixBom,
|
|
199
|
+
createOCamlBom,
|
|
172
200
|
createRustBom,
|
|
201
|
+
createSpackBom,
|
|
173
202
|
createSwiftBom,
|
|
174
203
|
createZigBom,
|
|
175
204
|
} from "./nativeBom.js";
|
|
@@ -2060,7 +2089,8 @@ export async function createXBom(path, options) {
|
|
|
2060
2089
|
`${options.multiProject ? "**/" : ""}cabal.project.freeze`,
|
|
2061
2090
|
options,
|
|
2062
2091
|
);
|
|
2063
|
-
|
|
2092
|
+
const stackLockDetectFiles = findStackLockFiles(path, options);
|
|
2093
|
+
if (hackageFiles.length || stackLockDetectFiles.length) {
|
|
2064
2094
|
return createHaskellBom(path, options);
|
|
2065
2095
|
}
|
|
2066
2096
|
|
|
@@ -2285,6 +2315,131 @@ export async function createXBom(path, options) {
|
|
|
2285
2315
|
if (gleamTomlFiles.length) {
|
|
2286
2316
|
return await createGleamBom(path, options);
|
|
2287
2317
|
}
|
|
2318
|
+
|
|
2319
|
+
// Julia
|
|
2320
|
+
const juliaProjectFiles = getAllFiles(
|
|
2321
|
+
path,
|
|
2322
|
+
`${options.multiProject ? "**/" : ""}Project.toml`,
|
|
2323
|
+
options,
|
|
2324
|
+
);
|
|
2325
|
+
const juliaManifestFiles = getAllFiles(
|
|
2326
|
+
path,
|
|
2327
|
+
`${options.multiProject ? "**/" : ""}Manifest.toml`,
|
|
2328
|
+
options,
|
|
2329
|
+
);
|
|
2330
|
+
// `Project.toml` is not a name Julia owns — Cloud Native Buildpacks use it
|
|
2331
|
+
// too — so dispatch only when a file actually declares a Julia environment.
|
|
2332
|
+
if (
|
|
2333
|
+
juliaManifestFiles.some(isJuliaManifestFile) ||
|
|
2334
|
+
juliaProjectFiles.some(isJuliaProjectFile)
|
|
2335
|
+
) {
|
|
2336
|
+
return await createJuliaBom(path, options);
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
// Erlang with rebar3
|
|
2340
|
+
const rebarLockFiles = getAllFiles(
|
|
2341
|
+
path,
|
|
2342
|
+
`${options.multiProject ? "**/" : ""}rebar.lock`,
|
|
2343
|
+
options,
|
|
2344
|
+
);
|
|
2345
|
+
if (rebarLockFiles.length) {
|
|
2346
|
+
return await createErlangBom(path, options);
|
|
2347
|
+
}
|
|
2348
|
+
|
|
2349
|
+
// OCaml with opam
|
|
2350
|
+
const opamLockedFiles = getAllFiles(
|
|
2351
|
+
path,
|
|
2352
|
+
`${options.multiProject ? "**/" : ""}*.opam.locked`,
|
|
2353
|
+
options,
|
|
2354
|
+
);
|
|
2355
|
+
if (opamLockedFiles.length) {
|
|
2356
|
+
return await createOCamlBom(path, options);
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
// Elm with elm.json (0.19) or elm-package.json (0.18)
|
|
2360
|
+
const elmJsonFiles = getAllFiles(
|
|
2361
|
+
path,
|
|
2362
|
+
`${options.multiProject ? "**/" : ""}elm.json`,
|
|
2363
|
+
options,
|
|
2364
|
+
).filter(isElmProjectFile);
|
|
2365
|
+
const legacyElmFiles = getAllFiles(
|
|
2366
|
+
path,
|
|
2367
|
+
`${options.multiProject ? "**/" : ""}elm-package.json`,
|
|
2368
|
+
options,
|
|
2369
|
+
);
|
|
2370
|
+
if (elmJsonFiles.length || legacyElmFiles.length) {
|
|
2371
|
+
return await createElmBom(path, options);
|
|
2372
|
+
}
|
|
2373
|
+
|
|
2374
|
+
// Crystal with shards
|
|
2375
|
+
const shardYmlFiles = getAllFiles(
|
|
2376
|
+
path,
|
|
2377
|
+
`${options.multiProject ? "**/" : ""}shard.yml`,
|
|
2378
|
+
options,
|
|
2379
|
+
);
|
|
2380
|
+
if (shardYmlFiles.length) {
|
|
2381
|
+
return await createCrystalBom(path, options);
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
// Nim with nimble
|
|
2385
|
+
const nimbleFiles = getAllFiles(
|
|
2386
|
+
path,
|
|
2387
|
+
`${options.multiProject ? "**/" : ""}*.nimble`,
|
|
2388
|
+
options,
|
|
2389
|
+
);
|
|
2390
|
+
if (nimbleFiles.length) {
|
|
2391
|
+
return await createNimBom(path, options);
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
// Lua with LuaRocks
|
|
2395
|
+
const rockspecFiles = getAllFiles(
|
|
2396
|
+
path,
|
|
2397
|
+
`${options.multiProject ? "**/" : ""}*.rockspec`,
|
|
2398
|
+
options,
|
|
2399
|
+
);
|
|
2400
|
+
if (rockspecFiles.length) {
|
|
2401
|
+
return await createLuaBom(path, options);
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
// Spack environments
|
|
2405
|
+
const spackLockFiles = getAllFiles(
|
|
2406
|
+
path,
|
|
2407
|
+
`${options.multiProject ? "**/" : ""}spack.lock`,
|
|
2408
|
+
options,
|
|
2409
|
+
);
|
|
2410
|
+
if (spackLockFiles.length) {
|
|
2411
|
+
return await createSpackBom(path, options);
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2414
|
+
// R with renv
|
|
2415
|
+
const renvLockFiles = getAllFiles(
|
|
2416
|
+
path,
|
|
2417
|
+
`${options.multiProject ? "**/" : ""}renv.lock`,
|
|
2418
|
+
options,
|
|
2419
|
+
);
|
|
2420
|
+
if (renvLockFiles.length) {
|
|
2421
|
+
return createRBom(path, options);
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
// Perl with Carton
|
|
2425
|
+
const cpanSnapshotFiles = getAllFiles(
|
|
2426
|
+
path,
|
|
2427
|
+
`${options.multiProject ? "**/" : ""}cpanfile.snapshot`,
|
|
2428
|
+
options,
|
|
2429
|
+
);
|
|
2430
|
+
if (cpanSnapshotFiles.length) {
|
|
2431
|
+
return createPerlBom(path, options);
|
|
2432
|
+
}
|
|
2433
|
+
|
|
2434
|
+
// Terraform and OpenTofu providers
|
|
2435
|
+
const tfLockFiles = getAllFiles(
|
|
2436
|
+
path,
|
|
2437
|
+
`${options.multiProject ? "**/" : ""}.terraform.lock.hcl`,
|
|
2438
|
+
options,
|
|
2439
|
+
);
|
|
2440
|
+
if (tfLockFiles.length) {
|
|
2441
|
+
return createTerraformBom(path, options);
|
|
2442
|
+
}
|
|
2288
2443
|
}
|
|
2289
2444
|
|
|
2290
2445
|
/**
|
|
@@ -2636,6 +2791,39 @@ async function createBomForPath(path, options) {
|
|
|
2636
2791
|
if (PROJECT_TYPE_ALIASES["gleam"].includes(projectType[0])) {
|
|
2637
2792
|
return await createGleamBom(path, options);
|
|
2638
2793
|
}
|
|
2794
|
+
if (PROJECT_TYPE_ALIASES["julia"].includes(projectType[0])) {
|
|
2795
|
+
return await createJuliaBom(path, options);
|
|
2796
|
+
}
|
|
2797
|
+
if (PROJECT_TYPE_ALIASES["erlang"].includes(projectType[0])) {
|
|
2798
|
+
return await createErlangBom(path, options);
|
|
2799
|
+
}
|
|
2800
|
+
if (PROJECT_TYPE_ALIASES["ocaml"].includes(projectType[0])) {
|
|
2801
|
+
return await createOCamlBom(path, options);
|
|
2802
|
+
}
|
|
2803
|
+
if (PROJECT_TYPE_ALIASES["elm"].includes(projectType[0])) {
|
|
2804
|
+
return await createElmBom(path, options);
|
|
2805
|
+
}
|
|
2806
|
+
if (PROJECT_TYPE_ALIASES["crystal"].includes(projectType[0])) {
|
|
2807
|
+
return await createCrystalBom(path, options);
|
|
2808
|
+
}
|
|
2809
|
+
if (PROJECT_TYPE_ALIASES["nim"].includes(projectType[0])) {
|
|
2810
|
+
return await createNimBom(path, options);
|
|
2811
|
+
}
|
|
2812
|
+
if (PROJECT_TYPE_ALIASES["lua"].includes(projectType[0])) {
|
|
2813
|
+
return await createLuaBom(path, options);
|
|
2814
|
+
}
|
|
2815
|
+
if (PROJECT_TYPE_ALIASES["spack"].includes(projectType[0])) {
|
|
2816
|
+
return await createSpackBom(path, options);
|
|
2817
|
+
}
|
|
2818
|
+
if (PROJECT_TYPE_ALIASES["r"].includes(projectType[0])) {
|
|
2819
|
+
return createRBom(path, options);
|
|
2820
|
+
}
|
|
2821
|
+
if (PROJECT_TYPE_ALIASES["perl"].includes(projectType[0])) {
|
|
2822
|
+
return createPerlBom(path, options);
|
|
2823
|
+
}
|
|
2824
|
+
if (PROJECT_TYPE_ALIASES["terraform"].includes(projectType[0])) {
|
|
2825
|
+
return createTerraformBom(path, options);
|
|
2826
|
+
}
|
|
2639
2827
|
if (PROJECT_TYPE_ALIASES["caxa"].includes(projectType[0])) {
|
|
2640
2828
|
return await createCaxaBom(path, options);
|
|
2641
2829
|
}
|
|
@@ -2645,6 +2833,9 @@ async function createBomForPath(path, options) {
|
|
|
2645
2833
|
if (PROJECT_TYPE_ALIASES["vscode-extension"].includes(projectType[0])) {
|
|
2646
2834
|
return await createVscodeExtensionBom(path, options);
|
|
2647
2835
|
}
|
|
2836
|
+
if (PROJECT_TYPE_ALIASES["agentic"].includes(projectType[0])) {
|
|
2837
|
+
return await createAgenticBom(path, options);
|
|
2838
|
+
}
|
|
2648
2839
|
if (PROJECT_TYPE_ALIASES["chrome-extension"].includes(projectType[0])) {
|
|
2649
2840
|
return await createChromeExtensionBom(path, options);
|
|
2650
2841
|
}
|
package/lib/cli/jsBom.js
CHANGED
|
@@ -53,6 +53,10 @@ import {
|
|
|
53
53
|
fetchHuggingFaceAssetInventory,
|
|
54
54
|
normalizeHuggingFaceReference,
|
|
55
55
|
} from "../ecosystems/remote/huggingface.js";
|
|
56
|
+
import {
|
|
57
|
+
AGENTIC_TOOL_PURL_TYPE,
|
|
58
|
+
collectAgenticTools,
|
|
59
|
+
} from "../helpers/agenticToolutils.js";
|
|
56
60
|
import {
|
|
57
61
|
cleanupTempDir,
|
|
58
62
|
collectInstalledExtensions,
|
|
@@ -100,6 +104,13 @@ const isWin = _platform() === "win32";
|
|
|
100
104
|
* local Modelfile/`.gguf` file input. Returns the explicit selection from
|
|
101
105
|
* `getExactAiInventoryType` when one is present.
|
|
102
106
|
*
|
|
107
|
+
* Direct HuggingFace interpretation of the source path is opt-in: only
|
|
108
|
+
* unambiguous references (`pkg:huggingface/...` purls and huggingface.co
|
|
109
|
+
* URLs) are recognized on their own. Bare `owner/repo`-shaped values are
|
|
110
|
+
* ordinary relative paths (eg: `repotests/sveltejs-realworld`) unless an AI
|
|
111
|
+
* inventory type such as `-t ai` is explicitly selected, in which case
|
|
112
|
+
* `getExactAiInventoryType` already returned it above.
|
|
113
|
+
*
|
|
103
114
|
* @param {string} path Project or file path
|
|
104
115
|
* @param {object} options CLI options
|
|
105
116
|
* @returns {string|undefined} The detected AI inventory type (`"ai"`) or undefined
|
|
@@ -109,7 +120,7 @@ export function getDirectAiInventoryType(path, options) {
|
|
|
109
120
|
if (exactAiInventoryType) {
|
|
110
121
|
return exactAiInventoryType;
|
|
111
122
|
}
|
|
112
|
-
if (normalizeHuggingFaceReference(path)) {
|
|
123
|
+
if (normalizeHuggingFaceReference(path, { explicitOnly: true })) {
|
|
113
124
|
return "ai";
|
|
114
125
|
}
|
|
115
126
|
try {
|
|
@@ -157,8 +168,10 @@ export async function createNodejsBom(path, options) {
|
|
|
157
168
|
excludedAiInventoryTypes,
|
|
158
169
|
);
|
|
159
170
|
let aiInventory = { components: [], dependencies: [], services: [] };
|
|
171
|
+
// A value that exists on the local filesystem is always a project path -
|
|
172
|
+
// never a remote model id - so existing inputs skip remote resolution.
|
|
160
173
|
const directHuggingFaceSource =
|
|
161
|
-
exactAiInventoryType === "ai"
|
|
174
|
+
exactAiInventoryType === "ai" && !safeExistsSync(path)
|
|
162
175
|
? normalizeHuggingFaceReference(path)
|
|
163
176
|
: undefined;
|
|
164
177
|
if (directHuggingFaceSource?.repoId) {
|
|
@@ -1748,6 +1761,50 @@ export async function createVscodeExtensionBom(path, options) {
|
|
|
1748
1761
|
});
|
|
1749
1762
|
}
|
|
1750
1763
|
|
|
1764
|
+
/**
|
|
1765
|
+
* Create a BOM that catalogs agentic CLI tools installed for the current user
|
|
1766
|
+
* (for example Kiro CLI, zcode, opencode, and Claude Code), along with the
|
|
1767
|
+
* agents, plugins, and providers they define.
|
|
1768
|
+
*
|
|
1769
|
+
* The scan is read-only and value-redacting: it records tool versions where a
|
|
1770
|
+
* declarative source exists, plus structural counts, but never reads
|
|
1771
|
+
* credentials, transcripts, session logs, or telemetry.
|
|
1772
|
+
*
|
|
1773
|
+
* @param {string} path Positional input. A host scan does not read a project
|
|
1774
|
+
* tree, so an explicit path other than the current directory is rejected
|
|
1775
|
+
* rather than silently ignored.
|
|
1776
|
+
* @param {Object} options Parse options from the CLI
|
|
1777
|
+
* @returns {Promise<Object>} Promise resolving to BOM data
|
|
1778
|
+
*/
|
|
1779
|
+
export async function createAgenticBom(path, options) {
|
|
1780
|
+
// Guard against a surprising host-wide scan masquerading as a project scan.
|
|
1781
|
+
// cdxgen always supplies a positional path (defaulting to "."), so only an
|
|
1782
|
+
// explicit path that resolves somewhere other than the current directory is
|
|
1783
|
+
// treated as a mistake.
|
|
1784
|
+
const resolvedPath = path ? resolve(path) : process.cwd();
|
|
1785
|
+
if (resolvedPath !== process.cwd()) {
|
|
1786
|
+
throw new Error(
|
|
1787
|
+
"The 'agentic' project type performs a host-wide scan of installed " +
|
|
1788
|
+
"agentic CLI tool directories and does not accept a path argument. " +
|
|
1789
|
+
`Re-run without the path (received '${path}').`,
|
|
1790
|
+
);
|
|
1791
|
+
}
|
|
1792
|
+
// Must not go to stdout: every entry point keeps stdout reserved for the BOM
|
|
1793
|
+
// payload so `cdxgen -t agentic -o -` stays pipeable.
|
|
1794
|
+
thoughtLog(
|
|
1795
|
+
"Scanning the current user's home directory for installed agentic CLI tools.",
|
|
1796
|
+
);
|
|
1797
|
+
const inventory = collectAgenticTools(options);
|
|
1798
|
+
const pkgList = trimComponents(inventory.components || []);
|
|
1799
|
+
return buildBomNSData(options, pkgList, AGENTIC_TOOL_PURL_TYPE, {
|
|
1800
|
+
src: "~",
|
|
1801
|
+
filename: "agentic-cli-tools",
|
|
1802
|
+
nsMapping: {},
|
|
1803
|
+
dependencies: inventory.dependencies || [],
|
|
1804
|
+
services: inventory.services || [],
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1751
1808
|
/**
|
|
1752
1809
|
* Function to create BOM for Electron ASAR archives.
|
|
1753
1810
|
*
|
package/lib/cli/jvmBom.js
CHANGED
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
parseGradleInfoLogsForUrls,
|
|
50
50
|
parseGradleProperties,
|
|
51
51
|
parseGradleResolvedDistributions,
|
|
52
|
+
parseGradleVersionCatalog,
|
|
52
53
|
recordGradleInvocationFailure,
|
|
53
54
|
splitOutputByGradleProjects,
|
|
54
55
|
} from "../ecosystems/gradleutils.js";
|
|
@@ -1372,6 +1373,27 @@ export async function createJavaBom(path, options) {
|
|
|
1372
1373
|
jarNSMapping = { ...jarNSMapping, ...tmpjarNSMapping };
|
|
1373
1374
|
}
|
|
1374
1375
|
}
|
|
1376
|
+
|
|
1377
|
+
// A version catalog declares coordinates without resolving them, so it
|
|
1378
|
+
// is used only when Gradle produced no dependency information at all.
|
|
1379
|
+
// The emitted components carry cdx:gradle:catalog=true to mark them as
|
|
1380
|
+
// declared rather than resolved.
|
|
1381
|
+
if (!pkgList.length) {
|
|
1382
|
+
const catalogFiles = getAllFiles(
|
|
1383
|
+
path,
|
|
1384
|
+
`${options.multiProject ? "**/" : ""}gradle/libs.versions.toml`,
|
|
1385
|
+
options,
|
|
1386
|
+
);
|
|
1387
|
+
for (const catalogFile of catalogFiles) {
|
|
1388
|
+
if (DEBUG_MODE) {
|
|
1389
|
+
console.log(`Parsing ${catalogFile}`);
|
|
1390
|
+
}
|
|
1391
|
+
const dlist = parseGradleVersionCatalog(catalogFile);
|
|
1392
|
+
if (dlist?.length) {
|
|
1393
|
+
pkgList = pkgList.concat(dlist);
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1375
1397
|
}
|
|
1376
1398
|
|
|
1377
1399
|
// Bazel
|
package/lib/cli/managedBom.js
CHANGED
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
parseGitHubWorkflowData,
|
|
51
51
|
parseHelmYamlData,
|
|
52
52
|
} from "../ecosystems/parsers-misc.js";
|
|
53
|
+
import { parseCpanSnapshot } from "../ecosystems/parsers-perl.js";
|
|
53
54
|
import {
|
|
54
55
|
generatePixiLockFile,
|
|
55
56
|
parseMojoProject,
|
|
@@ -61,6 +62,8 @@ import {
|
|
|
61
62
|
parseReqFile,
|
|
62
63
|
parseSetupPyFile,
|
|
63
64
|
} from "../ecosystems/parsers-python.js";
|
|
65
|
+
import { parseRenvLock } from "../ecosystems/parsers-r.js";
|
|
66
|
+
import { parseTerraformLockFile } from "../ecosystems/parsers-terraform.js";
|
|
64
67
|
import { collectEmbeddedSboms } from "../ecosystems/pep770.js";
|
|
65
68
|
import { isPyLockFile } from "../ecosystems/pylockutils.js";
|
|
66
69
|
import {
|
|
@@ -2150,3 +2153,152 @@ export async function createCryptoCertsBom(path, options) {
|
|
|
2150
2153
|
},
|
|
2151
2154
|
};
|
|
2152
2155
|
}
|
|
2156
|
+
|
|
2157
|
+
/**
|
|
2158
|
+
* Function to create bom string for R projects using renv.
|
|
2159
|
+
*
|
|
2160
|
+
* The `renv.lock` file carries the resolved package set for the project
|
|
2161
|
+
* library, including the R version it was produced under.
|
|
2162
|
+
*
|
|
2163
|
+
* @param {string} path to the project
|
|
2164
|
+
* @param {Object} options Parse options from the cli
|
|
2165
|
+
* @returns {Object} BOM object
|
|
2166
|
+
*/
|
|
2167
|
+
export function createRBom(path, options) {
|
|
2168
|
+
let pkgList = [];
|
|
2169
|
+
let dependencies = [];
|
|
2170
|
+
let rootInputs = [];
|
|
2171
|
+
let rVersion;
|
|
2172
|
+
const renvLockFiles = getAllFiles(
|
|
2173
|
+
path,
|
|
2174
|
+
`${options.multiProject ? "**/" : ""}renv.lock`,
|
|
2175
|
+
options,
|
|
2176
|
+
);
|
|
2177
|
+
for (const renvLockFile of renvLockFiles) {
|
|
2178
|
+
if (DEBUG_MODE) {
|
|
2179
|
+
console.log(`Parsing ${renvLockFile}`);
|
|
2180
|
+
}
|
|
2181
|
+
const result = parseRenvLock(renvLockFile);
|
|
2182
|
+
if (result.pkgList?.length) {
|
|
2183
|
+
pkgList = pkgList.concat(result.pkgList);
|
|
2184
|
+
}
|
|
2185
|
+
if (result.dependencies?.length) {
|
|
2186
|
+
dependencies = dependencies.concat(result.dependencies);
|
|
2187
|
+
}
|
|
2188
|
+
if (result.rootInputs?.length) {
|
|
2189
|
+
rootInputs = rootInputs.concat(result.rootInputs);
|
|
2190
|
+
}
|
|
2191
|
+
if (!rVersion) {
|
|
2192
|
+
rVersion = result.rVersion;
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
if (!pkgList.length) {
|
|
2196
|
+
return {};
|
|
2197
|
+
}
|
|
2198
|
+
// renv locks the library, not the project: they carry no project name, so
|
|
2199
|
+
// the directory is the name the project is already known by. The R version
|
|
2200
|
+
// the library was resolved under is a property of that project.
|
|
2201
|
+
const projectName = basename(resolve(path));
|
|
2202
|
+
const parentComponent = {
|
|
2203
|
+
type: "application",
|
|
2204
|
+
name: projectName,
|
|
2205
|
+
"bom-ref": `application:${projectName}:latest`,
|
|
2206
|
+
description: `R project: ${projectName}`,
|
|
2207
|
+
properties: [
|
|
2208
|
+
{ name: "internal:SrcFile", value: renvLockFiles.join(", ") },
|
|
2209
|
+
...(rVersion ? [{ name: "cdx:renv:rVersion", value: rVersion }] : []),
|
|
2210
|
+
],
|
|
2211
|
+
};
|
|
2212
|
+
if (rootInputs.length) {
|
|
2213
|
+
dependencies.push({
|
|
2214
|
+
ref: parentComponent["bom-ref"],
|
|
2215
|
+
dependsOn: [...new Set(rootInputs)].sort(),
|
|
2216
|
+
});
|
|
2217
|
+
}
|
|
2218
|
+
return buildBomNSData(options, pkgList, "cran", {
|
|
2219
|
+
src: path,
|
|
2220
|
+
filename: renvLockFiles.join(", "),
|
|
2221
|
+
dependencies,
|
|
2222
|
+
parentComponent,
|
|
2223
|
+
});
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
/**
|
|
2227
|
+
* Function to create bom string for Perl projects using Carton.
|
|
2228
|
+
*
|
|
2229
|
+
* The `cpanfile.snapshot` carries the resolved install set; the declared
|
|
2230
|
+
* `cpanfile` is consulted to distinguish direct dependencies.
|
|
2231
|
+
*
|
|
2232
|
+
* @param {string} path to the project
|
|
2233
|
+
* @param {Object} options Parse options from the cli
|
|
2234
|
+
* @returns {Object} BOM object
|
|
2235
|
+
*/
|
|
2236
|
+
export function createPerlBom(path, options) {
|
|
2237
|
+
let pkgList = [];
|
|
2238
|
+
let dependencies = [];
|
|
2239
|
+
const snapshotFiles = getAllFiles(
|
|
2240
|
+
path,
|
|
2241
|
+
`${options.multiProject ? "**/" : ""}cpanfile.snapshot`,
|
|
2242
|
+
options,
|
|
2243
|
+
);
|
|
2244
|
+
for (const snapshotFile of snapshotFiles) {
|
|
2245
|
+
if (DEBUG_MODE) {
|
|
2246
|
+
console.log(`Parsing ${snapshotFile}`);
|
|
2247
|
+
}
|
|
2248
|
+
const baseDir = dirname(snapshotFile);
|
|
2249
|
+
const cpanfile = join(baseDir, "cpanfile");
|
|
2250
|
+
const result = parseCpanSnapshot(
|
|
2251
|
+
snapshotFile,
|
|
2252
|
+
safeExistsSync(cpanfile) ? cpanfile : undefined,
|
|
2253
|
+
);
|
|
2254
|
+
if (result.pkgList?.length) {
|
|
2255
|
+
pkgList = pkgList.concat(result.pkgList);
|
|
2256
|
+
}
|
|
2257
|
+
if (result.dependencies?.length) {
|
|
2258
|
+
dependencies = dependencies.concat(result.dependencies);
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
if (pkgList.length) {
|
|
2262
|
+
return buildBomNSData(options, pkgList, "cpan", {
|
|
2263
|
+
src: path,
|
|
2264
|
+
filename: snapshotFiles.join(", "),
|
|
2265
|
+
dependencies,
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2268
|
+
return {};
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
/**
|
|
2272
|
+
* Function to create bom string for Terraform and OpenTofu projects.
|
|
2273
|
+
*
|
|
2274
|
+
* The `.terraform.lock.hcl` file pins the providers the configuration
|
|
2275
|
+
* resolves to, with content hashes suitable for the CycloneDX hashes array.
|
|
2276
|
+
*
|
|
2277
|
+
* @param {string} path to the project
|
|
2278
|
+
* @param {Object} options Parse options from the cli
|
|
2279
|
+
* @returns {Object} BOM object
|
|
2280
|
+
*/
|
|
2281
|
+
export function createTerraformBom(path, options) {
|
|
2282
|
+
let pkgList = [];
|
|
2283
|
+
const lockFiles = getAllFiles(
|
|
2284
|
+
path,
|
|
2285
|
+
`${options.multiProject ? "**/" : ""}.terraform.lock.hcl`,
|
|
2286
|
+
options,
|
|
2287
|
+
);
|
|
2288
|
+
for (const lockFile of lockFiles) {
|
|
2289
|
+
if (DEBUG_MODE) {
|
|
2290
|
+
console.log(`Parsing ${lockFile}`);
|
|
2291
|
+
}
|
|
2292
|
+
const result = parseTerraformLockFile(lockFile);
|
|
2293
|
+
if (result.pkgList?.length) {
|
|
2294
|
+
pkgList = pkgList.concat(result.pkgList);
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
if (pkgList.length) {
|
|
2298
|
+
return buildBomNSData(options, pkgList, "terraform", {
|
|
2299
|
+
src: path,
|
|
2300
|
+
filename: lockFiles.join(", "),
|
|
2301
|
+
});
|
|
2302
|
+
}
|
|
2303
|
+
return {};
|
|
2304
|
+
}
|