@cdxgen/cdxgen 13.0.1 → 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 +30 -16
- package/bin/audit.js +6 -0
- package/bin/cdxgen.js +141 -7
- package/bin/evinse.js +3 -1
- package/data/component-tags.json +8 -1
- package/data/crypto-oid.json +88 -12
- package/data/frameworks-list.json +86 -1
- package/data/remediations.json +1167 -0
- package/data/rules/ai-bom.yaml +78 -0
- package/data/rules/asar-archives.yaml +1 -1
- package/data/rules/build-fidelity.yaml +782 -0
- package/data/rules/cargo-rust.yaml +132 -0
- package/data/rules/mcp-servers.yaml +122 -0
- package/data/rules/package-integrity.yaml +13 -13
- package/lib/audit/index.js +48 -4
- package/lib/audit/scoring.js +2 -8
- package/lib/audit/targets.js +6 -1
- package/lib/cli/bomAssembly.js +32 -1
- package/lib/cli/cliOptions.js +94 -7
- package/lib/cli/index.js +268 -49
- package/lib/cli/jsBom.js +91 -5
- package/lib/cli/jvmBom.js +1515 -1314
- package/lib/cli/managedBom.js +249 -28
- package/lib/cli/nativeBom.js +986 -10
- package/lib/core/activity.js +120 -2
- package/lib/core/buildLedger.js +799 -0
- package/lib/core/deferredExit.js +141 -0
- package/lib/core/env.js +108 -2
- package/lib/core/fs.js +60 -0
- package/lib/core/logger.js +12 -99
- package/lib/core/severity.js +16 -0
- package/lib/core/syncFileWriter.js +106 -0
- 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 +250 -91
- package/lib/ecosystems/golem.js +11 -1
- package/lib/ecosystems/gradleutils.js +498 -17
- 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-js.js +26 -0
- package/lib/ecosystems/parsers-julia.js +268 -0
- package/lib/ecosystems/parsers-jvm.js +9 -0
- package/lib/ecosystems/parsers-lua.js +218 -0
- package/lib/ecosystems/parsers-misc.js +188 -2
- 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 +172 -36
- package/lib/ecosystems/parsers-r.js +148 -0
- package/lib/ecosystems/parsers-rebar.js +411 -0
- package/lib/ecosystems/parsers-rust.js +944 -19
- 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/pypiClassifiers.js +326 -0
- package/lib/ecosystems/pythonutils.js +49 -1
- package/lib/ecosystems/rubyutils.js +13 -0
- package/lib/ecosystems/rusi.js +126 -6
- package/lib/evinser/evinser.js +141 -13
- package/lib/helpers/agenticToolutils.js +925 -0
- package/lib/helpers/remote/dependency-track.js +81 -14
- 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 +17 -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/depsUtils.js +72 -0
- package/lib/inventory/dosai.js +508 -22
- package/lib/inventory/envcontext.js +215 -24
- package/lib/inventory/evidenceUtils.js +13 -0
- package/lib/inventory/fetchBatch.js +131 -2
- package/lib/inventory/fetchRate.js +74 -11
- package/lib/inventory/forgeEnricher.js +3 -2
- package/lib/inventory/jvmToolEnv.js +594 -0
- 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/osinfo.js +1 -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/inventory/toolRequirements.js +903 -0
- package/lib/managers/binary.js +24 -0
- package/lib/managers/docker.js +26 -5
- package/lib/parsers/huggingfaceUtils.js +15 -7
- package/lib/parsers/onnx.js +294 -0
- package/lib/parsers/safetensors.js +114 -0
- package/lib/server/server.js +1 -1
- package/lib/stages/postgen/annotationBuilder.js +97 -0
- package/lib/stages/postgen/auditBom.js +76 -79
- package/lib/stages/postgen/introspection/annotate.js +320 -0
- package/lib/stages/postgen/introspection/commandFacts.js +293 -0
- package/lib/stages/postgen/introspection/emit.js +192 -0
- package/lib/stages/postgen/introspection/formulationEvidence.js +427 -0
- package/lib/stages/postgen/introspection/markers.js +250 -0
- package/lib/stages/postgen/introspection/reflect.js +1214 -0
- package/lib/stages/postgen/introspection/report.js +1208 -0
- package/lib/stages/postgen/introspection/score.js +1067 -0
- package/lib/stages/postgen/introspection/shapeCommand.js +304 -0
- package/lib/stages/postgen/parentEdge.js +156 -0
- package/lib/stages/postgen/postgen.js +284 -3
- package/lib/stages/postgen/ruleEngine.js +17 -0
- package/lib/stages/pregen/envAudit.js +42 -2
- package/lib/stages/pregen/pregen.js +1171 -6
- package/lib/third-party/arborist/snapshots/calc-dep-flags.test.cjs +462 -0
- package/lib/validator/bomValidator.js +11 -2
- package/package.json +26 -26
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/audit/scoring.d.ts +2 -8
- package/types/lib/audit/scoring.d.ts.map +1 -1
- package/types/lib/audit/targets.d.ts.map +1 -1
- package/types/lib/cli/bomAssembly.d.ts.map +1 -1
- package/types/lib/cli/cliOptions.d.ts +2 -1
- package/types/lib/cli/cliOptions.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts +10 -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/buildLedger.d.ts +272 -0
- package/types/lib/core/buildLedger.d.ts.map +1 -0
- package/types/lib/core/deferredExit.d.ts +84 -0
- package/types/lib/core/deferredExit.d.ts.map +1 -0
- package/types/lib/core/env.d.ts +43 -1
- package/types/lib/core/env.d.ts.map +1 -1
- package/types/lib/core/fs.d.ts +21 -0
- package/types/lib/core/fs.d.ts.map +1 -1
- package/types/lib/core/logger.d.ts +2 -11
- package/types/lib/core/logger.d.ts.map +1 -1
- package/types/lib/core/severity.d.ts +11 -0
- package/types/lib/core/severity.d.ts.map +1 -0
- package/types/lib/core/syncFileWriter.d.ts +33 -0
- package/types/lib/core/syncFileWriter.d.ts.map +1 -0
- 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 +53 -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-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-jvm.d.ts.map +1 -1
- 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-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/pypiClassifiers.d.ts +80 -0
- package/types/lib/ecosystems/pypiClassifiers.d.ts.map +1 -0
- package/types/lib/ecosystems/pythonutils.d.ts +21 -1
- package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rusi.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +34 -1
- 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/helpers/remote/dependency-track.d.ts +45 -4
- package/types/lib/helpers/remote/dependency-track.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/auditCategories.d.ts +12 -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/depsUtils.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +43 -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 +43 -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 +190 -0
- package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -0
- 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/osinfo.d.ts.map +1 -1
- 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/inventory/toolRequirements.d.ts +216 -0
- package/types/lib/inventory/toolRequirements.d.ts.map +1 -0
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts.map +1 -1
- 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/annotationBuilder.d.ts +53 -0
- package/types/lib/stages/postgen/annotationBuilder.d.ts.map +1 -0
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
- package/types/lib/stages/postgen/introspection/annotate.d.ts +81 -0
- package/types/lib/stages/postgen/introspection/annotate.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/commandFacts.d.ts +32 -0
- package/types/lib/stages/postgen/introspection/commandFacts.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/emit.d.ts +71 -0
- package/types/lib/stages/postgen/introspection/emit.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/formulationEvidence.d.ts +154 -0
- package/types/lib/stages/postgen/introspection/formulationEvidence.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/markers.d.ts +58 -0
- package/types/lib/stages/postgen/introspection/markers.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/reflect.d.ts +77 -0
- package/types/lib/stages/postgen/introspection/reflect.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/report.d.ts +85 -0
- package/types/lib/stages/postgen/introspection/report.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/score.d.ts +149 -0
- package/types/lib/stages/postgen/introspection/score.d.ts.map +1 -0
- package/types/lib/stages/postgen/introspection/shapeCommand.d.ts +79 -0
- package/types/lib/stages/postgen/introspection/shapeCommand.d.ts.map +1 -0
- package/types/lib/stages/postgen/parentEdge.d.ts +35 -0
- package/types/lib/stages/postgen/parentEdge.d.ts.map +1 -0
- package/types/lib/stages/postgen/postgen.d.ts +35 -2
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
- package/types/lib/stages/pregen/pregen.d.ts +131 -0
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
import { parse as loadYaml } from "yaml";
|
|
4
|
+
|
|
5
|
+
import { tryBuildPurl } from "../inventory/purl.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Crystal parser for `shard.yml` and `shard.lock`.
|
|
9
|
+
*
|
|
10
|
+
* Shards resolves dependencies declared in `shard.yml` and records the
|
|
11
|
+
* resolved set in `shard.lock`, which pins each dependency's version and
|
|
12
|
+
* source repository. Both files are YAML and are read with the standard
|
|
13
|
+
* parser.
|
|
14
|
+
*
|
|
15
|
+
* No `crystal` purl type is registered, so shards are identified as generic
|
|
16
|
+
* packages carrying a `cdx:purl:proposedType=crystal` property, following
|
|
17
|
+
* the convention used for nix and zig. This keeps the BOM valid today and
|
|
18
|
+
* allows a mechanical migration if a type is registered upstream.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Parse a Crystal project from `shard.yml` and optional `shard.lock`.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} shardYmlFile Path to `shard.yml`
|
|
25
|
+
* @param {string} [shardLockFile] Path to `shard.lock`, if present
|
|
26
|
+
* @returns {{ pkgList: object[], dependencies: object[], parentComponent: object, rootInputs?: string[] }}
|
|
27
|
+
*/
|
|
28
|
+
export function parseShardsProject(shardYmlFile, shardLockFile) {
|
|
29
|
+
const manifest = readYamlFile(shardYmlFile);
|
|
30
|
+
|
|
31
|
+
const parentComponent = {};
|
|
32
|
+
if (typeof manifest?.name === "string" && manifest.name) {
|
|
33
|
+
parentComponent.type = "application";
|
|
34
|
+
parentComponent.name = manifest.name;
|
|
35
|
+
if (typeof manifest.version === "string" && manifest.version) {
|
|
36
|
+
parentComponent.version = manifest.version;
|
|
37
|
+
}
|
|
38
|
+
parentComponent.description =
|
|
39
|
+
typeof manifest.description === "string" && manifest.description
|
|
40
|
+
? manifest.description
|
|
41
|
+
: `Crystal shard: ${manifest.name}`;
|
|
42
|
+
parentComponent.properties = [
|
|
43
|
+
{ name: "internal:SrcFile", value: shardYmlFile },
|
|
44
|
+
];
|
|
45
|
+
if (typeof manifest.crystal === "string" && manifest.crystal) {
|
|
46
|
+
parentComponent.properties.push({
|
|
47
|
+
name: "cdx:crystal:languageVersion",
|
|
48
|
+
value: manifest.crystal,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const declared =
|
|
54
|
+
manifest?.dependencies && typeof manifest.dependencies === "object"
|
|
55
|
+
? Object.keys(manifest.dependencies)
|
|
56
|
+
: [];
|
|
57
|
+
const devDeclared =
|
|
58
|
+
manifest?.development_dependencies &&
|
|
59
|
+
typeof manifest.development_dependencies === "object"
|
|
60
|
+
? Object.keys(manifest.development_dependencies)
|
|
61
|
+
: [];
|
|
62
|
+
|
|
63
|
+
let lock;
|
|
64
|
+
if (shardLockFile) {
|
|
65
|
+
lock = readYamlFile(shardLockFile);
|
|
66
|
+
}
|
|
67
|
+
const lockedShards =
|
|
68
|
+
lock?.shards && typeof lock.shards === "object" ? lock.shards : undefined;
|
|
69
|
+
if (!lockedShards) {
|
|
70
|
+
// Lockless fallback: emit declared dependencies without resolved versions.
|
|
71
|
+
const pkgList = [
|
|
72
|
+
...declared.map((name) =>
|
|
73
|
+
crystalPackage(name, undefined, {
|
|
74
|
+
direct: true,
|
|
75
|
+
dev: false,
|
|
76
|
+
srcFile: shardYmlFile,
|
|
77
|
+
}),
|
|
78
|
+
),
|
|
79
|
+
...devDeclared.map((name) =>
|
|
80
|
+
crystalPackage(name, undefined, {
|
|
81
|
+
direct: true,
|
|
82
|
+
dev: true,
|
|
83
|
+
srcFile: shardYmlFile,
|
|
84
|
+
}),
|
|
85
|
+
),
|
|
86
|
+
];
|
|
87
|
+
return {
|
|
88
|
+
pkgList,
|
|
89
|
+
dependencies: [],
|
|
90
|
+
parentComponent,
|
|
91
|
+
rootInputs: pkgList.map((p) => p["bom-ref"]),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const directNames = new Set(declared);
|
|
96
|
+
const devNames = new Set(devDeclared);
|
|
97
|
+
const pkgList = [];
|
|
98
|
+
const refByName = new Map();
|
|
99
|
+
for (const [name, entry] of Object.entries(lockedShards)) {
|
|
100
|
+
const version =
|
|
101
|
+
typeof entry?.version === "string" && entry.version
|
|
102
|
+
? entry.version
|
|
103
|
+
: undefined;
|
|
104
|
+
const pkg = crystalPackage(name, version, {
|
|
105
|
+
direct: directNames.has(name),
|
|
106
|
+
dev: devNames.has(name),
|
|
107
|
+
srcFile: shardLockFile,
|
|
108
|
+
});
|
|
109
|
+
pkgList.push(pkg);
|
|
110
|
+
refByName.set(name, pkg["bom-ref"]);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// shard.lock records no dependency graph between shards, so the root links
|
|
114
|
+
// to the declared set and every other shard stands on its own version pin.
|
|
115
|
+
const rootInputs = [...directNames, ...devNames]
|
|
116
|
+
.map((name) => refByName.get(name))
|
|
117
|
+
.filter(Boolean);
|
|
118
|
+
return { pkgList, dependencies: [], parentComponent, rootInputs };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Build a component-like package record for a Crystal shard.
|
|
123
|
+
*
|
|
124
|
+
* @param {string} name Shard name
|
|
125
|
+
* @param {string|undefined} version Resolved version, if known
|
|
126
|
+
* @param {object} opts Extra context (`direct`, `dev`, `srcFile`)
|
|
127
|
+
* @returns {object} Package record
|
|
128
|
+
*/
|
|
129
|
+
function crystalPackage(name, version, opts) {
|
|
130
|
+
const purl = tryBuildPurl({
|
|
131
|
+
type: "generic",
|
|
132
|
+
name,
|
|
133
|
+
version: version || undefined,
|
|
134
|
+
});
|
|
135
|
+
const properties = [
|
|
136
|
+
{ name: "internal:SrcFile", value: opts.srcFile },
|
|
137
|
+
{ name: "cdx:purl:proposedType", value: "crystal" },
|
|
138
|
+
];
|
|
139
|
+
if (opts.direct) {
|
|
140
|
+
properties.push({
|
|
141
|
+
name: "cdx:crystal:dependency",
|
|
142
|
+
value: opts.dev ? "direct-dev" : "direct",
|
|
143
|
+
});
|
|
144
|
+
} else {
|
|
145
|
+
properties.push({ name: "cdx:crystal:dependency", value: "transitive" });
|
|
146
|
+
}
|
|
147
|
+
if (opts.dev) {
|
|
148
|
+
properties.push({ name: "cdx:crystal:scope", value: "development" });
|
|
149
|
+
}
|
|
150
|
+
const pkg = {
|
|
151
|
+
name,
|
|
152
|
+
...(version ? { version } : {}),
|
|
153
|
+
type: "library",
|
|
154
|
+
scope: opts.dev ? "optional" : "required",
|
|
155
|
+
properties,
|
|
156
|
+
};
|
|
157
|
+
if (purl) {
|
|
158
|
+
pkg.purl = purl;
|
|
159
|
+
pkg["bom-ref"] = decodeURIComponent(purl);
|
|
160
|
+
} else {
|
|
161
|
+
pkg["bom-ref"] = `library:${name}:${version || ""}`;
|
|
162
|
+
}
|
|
163
|
+
return pkg;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Read and parse a YAML file, warning instead of throwing.
|
|
168
|
+
*
|
|
169
|
+
* @param {string} filePath File to read
|
|
170
|
+
* @returns {object|undefined} Parsed value
|
|
171
|
+
*/
|
|
172
|
+
function readYamlFile(filePath) {
|
|
173
|
+
try {
|
|
174
|
+
return loadYaml(readFileSync(filePath, "utf-8"));
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.warn(`Failed to parse ${filePath}: ${error.message}`);
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -13,6 +13,34 @@ import { findLicenseId } from "../inventory/spdx.js";
|
|
|
13
13
|
import { xml2js } from "../parsers/xml.js";
|
|
14
14
|
import { extractPackageInfoFromHintPath } from "./dotnetutils.js";
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Apply a version to a NuGet component so that the `version` field and the purl
|
|
18
|
+
* always agree.
|
|
19
|
+
*
|
|
20
|
+
* A .NET manifest can state a version that is not a version: an MSBuild property
|
|
21
|
+
* such as `$(JsonVersion)`, a range such as `[3.13.3,4.0)`, a wildcard such as
|
|
22
|
+
* `2.0.*`, or nothing at all. Such a declaration cannot go into a purl, so a
|
|
23
|
+
* component that kept it in `version` while its purl carried none described one
|
|
24
|
+
* package two ways. A scanner range matching on the versionless purl then reports
|
|
25
|
+
* every advisory published against the package name.
|
|
26
|
+
*
|
|
27
|
+
* The declaration is not lost: callers record it as `cdx:nuget:declared_version_range`.
|
|
28
|
+
*
|
|
29
|
+
* @param {Object} pkg Component to update in place. `name` must already be set.
|
|
30
|
+
* @param {String} [version] Version as stated or resolved, concrete or not
|
|
31
|
+
*
|
|
32
|
+
* @returns {Object} The same component
|
|
33
|
+
*/
|
|
34
|
+
export function applyNugetVersion(pkg, version) {
|
|
35
|
+
const concrete = concreteVersion(version);
|
|
36
|
+
if (concrete) {
|
|
37
|
+
pkg.version = concrete;
|
|
38
|
+
} else {
|
|
39
|
+
delete pkg.version;
|
|
40
|
+
}
|
|
41
|
+
return applyPurl(pkg, nugetPurl(pkg.name, concrete));
|
|
42
|
+
}
|
|
43
|
+
|
|
16
44
|
/**
|
|
17
45
|
* Method to parse .nupkg files
|
|
18
46
|
*
|
|
@@ -140,16 +168,22 @@ export function parseNuspecData(nupkgFile, nuspecData) {
|
|
|
140
168
|
continue;
|
|
141
169
|
}
|
|
142
170
|
groupPkg.name = agroupdep.id;
|
|
171
|
+
let declaredRange;
|
|
143
172
|
if (agroupdep?.version) {
|
|
144
173
|
let versionStr = agroupdep.version;
|
|
145
174
|
// version could have square brackets around them
|
|
146
175
|
if (versionStr.startsWith("[") && versionStr.endsWith("]")) {
|
|
147
176
|
versionStr = versionStr.replace(/[\[\]]/g, "");
|
|
148
177
|
}
|
|
149
|
-
|
|
150
|
-
|
|
178
|
+
// A nuspec dependency states the range the package accepts, not the
|
|
179
|
+
// version installed. Anything that is not a single version stays a
|
|
180
|
+
// declaration so the component and its purl agree - #4359.
|
|
181
|
+
if (!concreteVersion(versionStr)) {
|
|
182
|
+
declaredRange = agroupdep.version;
|
|
183
|
+
}
|
|
184
|
+
applyNugetVersion(groupPkg, versionStr);
|
|
151
185
|
} else {
|
|
152
|
-
|
|
186
|
+
applyNugetVersion(groupPkg);
|
|
153
187
|
}
|
|
154
188
|
groupPkg.scope = "optional";
|
|
155
189
|
groupPkg.properties = [
|
|
@@ -158,6 +192,12 @@ export function parseNuspecData(nupkgFile, nuspecData) {
|
|
|
158
192
|
value: nupkgFile,
|
|
159
193
|
},
|
|
160
194
|
];
|
|
195
|
+
if (declaredRange) {
|
|
196
|
+
groupPkg.properties.push({
|
|
197
|
+
name: "cdx:nuget:declared_version_range",
|
|
198
|
+
value: declaredRange,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
161
201
|
if (targetFramework) {
|
|
162
202
|
groupPkg.properties.push({
|
|
163
203
|
name: "cdx:dotnet:target_framework",
|
|
@@ -243,20 +283,15 @@ export function parseCsPkgData(pkgData, pkgFile, pkgNameVersions = {}) {
|
|
|
243
283
|
// so the declaration stays visible, and the version is resolved from a
|
|
244
284
|
// more precise manifest so the purl names the package that is present.
|
|
245
285
|
let declaredRange;
|
|
246
|
-
if (!pkg.version
|
|
286
|
+
if (!concreteVersion(pkg.version)) {
|
|
247
287
|
confidence = 0.5;
|
|
288
|
+
declaredRange = pkg.version;
|
|
248
289
|
// Backfill from a version already resolved by a more precise manifest.
|
|
249
290
|
// Concrete versions are never overridden - a disagreement means both
|
|
250
291
|
// versions must be tracked.
|
|
251
|
-
pkg.version = pkgNameVersions[pkg.name]
|
|
252
|
-
} else if (/[[\](),*]/.test(pkg.version)) {
|
|
253
|
-
confidence = 0.5;
|
|
254
|
-
if (pkgNameVersions[pkg.name]) {
|
|
255
|
-
declaredRange = pkg.version;
|
|
256
|
-
pkg.version = pkgNameVersions[pkg.name];
|
|
257
|
-
}
|
|
292
|
+
pkg.version = pkgNameVersions[pkg.name];
|
|
258
293
|
}
|
|
259
|
-
|
|
294
|
+
applyNugetVersion(pkg, pkg.version);
|
|
260
295
|
if (pkgFile) {
|
|
261
296
|
pkg.properties = [
|
|
262
297
|
{
|
|
@@ -712,23 +747,17 @@ export function parseCsProjData(
|
|
|
712
747
|
const exactPin = pkg.version.match(/^\[([^,[\]()]+)\]$/);
|
|
713
748
|
if (exactPin) {
|
|
714
749
|
pkg.version = exactPin[1];
|
|
715
|
-
} else if (
|
|
716
|
-
pkg.version
|
|
717
|
-
|
|
718
|
-
) {
|
|
719
|
-
const resolved =
|
|
750
|
+
} else if (!concreteVersion(pkg.version)) {
|
|
751
|
+
declaredRange = pkg.version;
|
|
752
|
+
pkg.version =
|
|
720
753
|
pkgNameVersions[pkg.name] ||
|
|
721
754
|
centralVersions[pkg.name.toLowerCase()];
|
|
722
|
-
if (resolved) {
|
|
723
|
-
declaredRange = pkg.version;
|
|
724
|
-
pkg.version = resolved;
|
|
725
|
-
}
|
|
726
755
|
}
|
|
727
756
|
}
|
|
728
757
|
// A version that could not be resolved from any source must not be
|
|
729
758
|
// stringified into the purl - `@undefined` is not a version and makes the
|
|
730
759
|
// component unmatchable. Mirrors parseCsPkgData.
|
|
731
|
-
|
|
760
|
+
applyNugetVersion(pkg, pkg.version);
|
|
732
761
|
if (projFile) {
|
|
733
762
|
pkg.properties = [
|
|
734
763
|
{
|
|
@@ -821,26 +850,27 @@ export function parseCsProjData(
|
|
|
821
850
|
});
|
|
822
851
|
}
|
|
823
852
|
const version = hintVersion ?? assemblyVersion;
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
853
|
+
// An assembly reference that states no version anywhere - no HintPath to
|
|
854
|
+
// read one from and no `Version=` on the Include - leaves the component
|
|
855
|
+
// versionless in both fields. The registry's latest release is not a
|
|
856
|
+
// stand-in: `<Reference>` resolves an assembly from a targeting pack, a
|
|
857
|
+
// lib folder or the GAC, and the project does not say which package it
|
|
858
|
+
// came from. See #4359.
|
|
859
|
+
applyNugetVersion(pkg, version);
|
|
860
|
+
if (
|
|
861
|
+
!pkg.version &&
|
|
862
|
+
(pkg.name.startsWith("System.") ||
|
|
831
863
|
pkg.name.startsWith("Mono.") ||
|
|
832
|
-
pkg.name.startsWith("Microsoft.")
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
}
|
|
864
|
+
pkg.name.startsWith("Microsoft."))
|
|
865
|
+
) {
|
|
866
|
+
// If this is a System package, then track the target frameworks
|
|
867
|
+
for (const tf of projectTargetFrameworks) {
|
|
868
|
+
pkg.properties.push({
|
|
869
|
+
name: "cdx:dotnet:target_framework",
|
|
870
|
+
value: tf,
|
|
871
|
+
});
|
|
841
872
|
}
|
|
842
873
|
}
|
|
843
|
-
pkg["bom-ref"] = pkg.purl;
|
|
844
874
|
if (assemblyName) {
|
|
845
875
|
pkg.properties.push({
|
|
846
876
|
name: "cdx:dotnet:assembly_name",
|