@cdxgen/cdxgen 13.0.1 → 13.1.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 +26 -13
- package/bin/audit.js +6 -0
- package/bin/cdxgen.js +125 -4
- package/bin/evinse.js +1 -1
- package/data/component-tags.json +8 -1
- package/data/frameworks-list.json +86 -1
- package/data/remediations.json +1144 -0
- package/data/rules/asar-archives.yaml +1 -1
- package/data/rules/build-fidelity.yaml +782 -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/cli/bomAssembly.js +20 -1
- package/lib/cli/cliOptions.js +94 -7
- package/lib/cli/index.js +76 -48
- package/lib/cli/jsBom.js +32 -3
- package/lib/cli/jvmBom.js +1494 -1315
- package/lib/cli/managedBom.js +97 -28
- package/lib/cli/nativeBom.js +189 -10
- package/lib/core/buildLedger.js +799 -0
- package/lib/core/deferredExit.js +141 -0
- package/lib/core/env.js +69 -1
- 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/ecosystems/ecosystems.js +9 -0
- package/lib/ecosystems/gradleutils.js +355 -15
- package/lib/ecosystems/parsers-js.js +26 -0
- package/lib/ecosystems/parsers-jvm.js +9 -0
- package/lib/ecosystems/parsers-misc.js +16 -2
- package/lib/ecosystems/parsers-python.js +171 -35
- package/lib/ecosystems/parsers-rust.js +12 -2
- package/lib/ecosystems/pypiClassifiers.js +326 -0
- package/lib/ecosystems/pythonutils.js +49 -1
- package/lib/ecosystems/rubyutils.js +13 -0
- package/lib/evinser/evinser.js +30 -12
- package/lib/helpers/remote/dependency-track.js +81 -14
- package/lib/inventory/auditCategories.js +9 -0
- package/lib/inventory/depsUtils.js +72 -0
- package/lib/inventory/dosai.js +431 -22
- package/lib/inventory/envcontext.js +206 -18
- package/lib/inventory/fetchBatch.js +57 -0
- package/lib/inventory/jvmToolEnv.js +593 -0
- package/lib/inventory/osinfo.js +1 -0
- package/lib/inventory/toolRequirements.js +903 -0
- package/lib/managers/binary.js +24 -0
- package/lib/managers/docker.js +26 -5
- 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 +227 -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 +115 -2
- 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/validator/bomValidator.js +11 -2
- package/package.json +14 -14
- 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/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 +8 -0
- 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.map +1 -1
- package/types/lib/cli/managedBom.d.ts.map +1 -1
- package/types/lib/cli/nativeBom.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 +22 -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/ecosystems/ecosystems.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +33 -0
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- 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/pypiClassifiers.d.ts +80 -0
- package/types/lib/ecosystems/pypiClassifiers.d.ts.map +1 -0
- package/types/lib/ecosystems/pythonutils.d.ts +20 -0
- package/types/lib/ecosystems/pythonutils.d.ts.map +1 -1
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +5 -1
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- 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/auditCategories.d.ts +8 -0
- package/types/lib/inventory/auditCategories.d.ts.map +1 -1
- package/types/lib/inventory/depsUtils.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +20 -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/fetchBatch.d.ts +9 -0
- package/types/lib/inventory/fetchBatch.d.ts.map +1 -1
- package/types/lib/inventory/jvmToolEnv.d.ts +189 -0
- package/types/lib/inventory/jvmToolEnv.d.ts.map +1 -0
- package/types/lib/inventory/osinfo.d.ts.map +1 -1
- 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/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 +57 -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 +2 -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,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ecosystem marker detection for the build-introspection reflection step.
|
|
3
|
+
*
|
|
4
|
+
* A marker is a manifest or lockfile whose presence on disk proves an
|
|
5
|
+
* ecosystem was part of the scanned project. Markers drive two verdicts:
|
|
6
|
+
* an ecosystem with markers but zero components in the BOM is `absent`, and
|
|
7
|
+
* an ecosystem that has markers but no cdxgen project type at all is a
|
|
8
|
+
* coverage gap (`unsupported`), which is cdxgen's backlog rather than the
|
|
9
|
+
* user's problem.
|
|
10
|
+
*
|
|
11
|
+
* Detection is deliberately bounded: the scanned directory itself plus one
|
|
12
|
+
* level of immediate subdirectories. postProcess runs after generation, so a
|
|
13
|
+
* second full tree walk would be a measurable cost on large repos; markers
|
|
14
|
+
* deeper than one directory level are simply not seen, which is acceptable
|
|
15
|
+
* because tier assignment never relies on markers alone when the BOM already
|
|
16
|
+
* carries the ecosystem's components.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { readdirSync } from "node:fs";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
|
|
22
|
+
import { safeExistsSync } from "../../../core/fs.js";
|
|
23
|
+
|
|
24
|
+
/** Largest number of immediate subdirectories inspected at depth one. */
|
|
25
|
+
const MAX_SUBDIRS_SCANNED = 100;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Marker table: ecosystem → manifest and lockfile names that indicate the
|
|
29
|
+
* ecosystem is part of the project. Entries are either exact file names or
|
|
30
|
+
* `{ suffix }` matchers for extension-driven ecosystems. Ecosystems cdxgen
|
|
31
|
+
* cannot parse (elm, crystal, nim, perl, r) are included so the reflection
|
|
32
|
+
* can report them as coverage gaps instead of silently ignoring them.
|
|
33
|
+
*
|
|
34
|
+
* @type {Readonly<Record<string, {names: string[], suffixes: string[]}>>}
|
|
35
|
+
*/
|
|
36
|
+
export const ECOSYSTEM_MARKERS = Object.freeze({
|
|
37
|
+
java: {
|
|
38
|
+
names: [
|
|
39
|
+
"pom.xml",
|
|
40
|
+
"build.gradle",
|
|
41
|
+
"build.gradle.kts",
|
|
42
|
+
"settings.gradle",
|
|
43
|
+
"settings.gradle.kts",
|
|
44
|
+
"gradlew",
|
|
45
|
+
"build.sbt",
|
|
46
|
+
"mill-version",
|
|
47
|
+
".sdkmanrc",
|
|
48
|
+
],
|
|
49
|
+
suffixes: [],
|
|
50
|
+
},
|
|
51
|
+
npm: {
|
|
52
|
+
names: [
|
|
53
|
+
"package.json",
|
|
54
|
+
"package-lock.json",
|
|
55
|
+
"pnpm-lock.yaml",
|
|
56
|
+
"pnpm-workspace.yaml",
|
|
57
|
+
"yarn.lock",
|
|
58
|
+
"bun.lockb",
|
|
59
|
+
"bun.lock",
|
|
60
|
+
"deno.lock",
|
|
61
|
+
],
|
|
62
|
+
suffixes: [],
|
|
63
|
+
},
|
|
64
|
+
python: {
|
|
65
|
+
names: [
|
|
66
|
+
"requirements.txt",
|
|
67
|
+
"Pipfile",
|
|
68
|
+
"Pipfile.lock",
|
|
69
|
+
"pyproject.toml",
|
|
70
|
+
"poetry.lock",
|
|
71
|
+
"pdm.lock",
|
|
72
|
+
"uv.lock",
|
|
73
|
+
"setup.py",
|
|
74
|
+
"setup.cfg",
|
|
75
|
+
".python-version",
|
|
76
|
+
"environment.yml",
|
|
77
|
+
],
|
|
78
|
+
suffixes: [],
|
|
79
|
+
},
|
|
80
|
+
go: { names: ["go.mod", "go.sum", "go.work"], suffixes: [] },
|
|
81
|
+
rust: {
|
|
82
|
+
names: [
|
|
83
|
+
"Cargo.toml",
|
|
84
|
+
"Cargo.lock",
|
|
85
|
+
"rust-toolchain.toml",
|
|
86
|
+
"rust-toolchain",
|
|
87
|
+
],
|
|
88
|
+
suffixes: [],
|
|
89
|
+
},
|
|
90
|
+
ruby: { names: ["Gemfile", "Gemfile.lock", ".ruby-version"], suffixes: [] },
|
|
91
|
+
csharp: {
|
|
92
|
+
names: ["global.json", "nuget.config"],
|
|
93
|
+
suffixes: [".csproj", ".vbproj", ".fsproj", ".sln"],
|
|
94
|
+
},
|
|
95
|
+
php: { names: ["composer.json", "composer.lock"], suffixes: [] },
|
|
96
|
+
dart: { names: ["pubspec.yaml", "pubspec.lock"], suffixes: [] },
|
|
97
|
+
helm: { names: ["Chart.yaml", "Chart.yml"], suffixes: [] },
|
|
98
|
+
clojure: {
|
|
99
|
+
names: ["project.clj", "deps.edn", "bb.edn", "shadow-cljs.edn"],
|
|
100
|
+
suffixes: [],
|
|
101
|
+
},
|
|
102
|
+
cocoa: { names: ["Podfile", "Podfile.lock"], suffixes: [] },
|
|
103
|
+
swift: { names: ["Package.swift", "Package.resolved"], suffixes: [] },
|
|
104
|
+
elixir: { names: ["mix.exs", "mix.lock"], suffixes: [] },
|
|
105
|
+
c: {
|
|
106
|
+
names: ["CMakeLists.txt", "conanfile.txt", "conanfile.py"],
|
|
107
|
+
suffixes: [],
|
|
108
|
+
},
|
|
109
|
+
haskell: { names: ["cabal.project", "stack.yaml"], suffixes: [".cabal"] },
|
|
110
|
+
elm: { names: ["elm.json"], suffixes: [] },
|
|
111
|
+
crystal: { names: ["shard.yml", "shard.lock"], suffixes: [] },
|
|
112
|
+
nim: { names: ["nim.cfg", "config.nims"], suffixes: [".nimble"] },
|
|
113
|
+
perl: {
|
|
114
|
+
names: ["cpanfile", "META.json", "META.yml", "Makefile.PL", "Build.PL"],
|
|
115
|
+
suffixes: [],
|
|
116
|
+
},
|
|
117
|
+
r: { names: ["DESCRIPTION", "renv.lock"], suffixes: [] },
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
/** Marker file name → ecosystems claiming it, and marker suffix → claiming
|
|
121
|
+
* ecosystems, both built once from the table. The name index is exported so
|
|
122
|
+
* the reflection can recognize marker paths carried in ledger events without
|
|
123
|
+
* rescanning the filesystem. */
|
|
124
|
+
export const MARKERS_BY_NAME = new Map();
|
|
125
|
+
/** Marker suffix → ecosystems claiming it. */
|
|
126
|
+
const MARKERS_BY_SUFFIX = [];
|
|
127
|
+
for (const [ecosystem, markers] of Object.entries(ECOSYSTEM_MARKERS)) {
|
|
128
|
+
for (const name of markers.names) {
|
|
129
|
+
const ecosystems = MARKERS_BY_NAME.get(name) || [];
|
|
130
|
+
ecosystems.push(ecosystem);
|
|
131
|
+
MARKERS_BY_NAME.set(name, ecosystems);
|
|
132
|
+
}
|
|
133
|
+
for (const suffix of markers.suffixes) {
|
|
134
|
+
MARKERS_BY_SUFFIX.push({ ecosystem, suffix });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* List a directory's entries as plain `{ name, directory }` records, sorted by
|
|
140
|
+
* name so detection results are deterministic. Callers may inject this helper
|
|
141
|
+
* to bound or observe the scan in tests.
|
|
142
|
+
*
|
|
143
|
+
* @param {string} dirPath Directory to list.
|
|
144
|
+
* @returns {{name: string, directory: boolean}[]} Sorted entries.
|
|
145
|
+
*/
|
|
146
|
+
function listDirectory(dirPath) {
|
|
147
|
+
return readdirSync(dirPath, { withFileTypes: true })
|
|
148
|
+
.map((entry) => ({ name: entry.name, directory: entry.isDirectory() }))
|
|
149
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Match one directory's entries against the marker index and record the full
|
|
154
|
+
* paths of every marker found.
|
|
155
|
+
*
|
|
156
|
+
* @param {string} dirPath Directory the entries belong to.
|
|
157
|
+
* @param {{name: string, directory: boolean}[]} entries Directory entries.
|
|
158
|
+
* @param {Map<string, Set<string>>} markersByEcosystem Accumulator keyed by ecosystem.
|
|
159
|
+
* @returns {void}
|
|
160
|
+
*/
|
|
161
|
+
function scanEntries(dirPath, entries, markersByEcosystem) {
|
|
162
|
+
for (const entry of entries) {
|
|
163
|
+
const nameEcosystems = MARKERS_BY_NAME.get(entry.name);
|
|
164
|
+
if (nameEcosystems) {
|
|
165
|
+
for (const ecosystem of nameEcosystems) {
|
|
166
|
+
const paths = markersByEcosystem.get(ecosystem) || new Set();
|
|
167
|
+
paths.add(join(dirPath, entry.name));
|
|
168
|
+
markersByEcosystem.set(ecosystem, paths);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
for (const { ecosystem, suffix } of MARKERS_BY_SUFFIX) {
|
|
172
|
+
if (entry.name.length > suffix.length && entry.name.endsWith(suffix)) {
|
|
173
|
+
const paths = markersByEcosystem.get(ecosystem) || new Set();
|
|
174
|
+
paths.add(join(dirPath, entry.name));
|
|
175
|
+
markersByEcosystem.set(ecosystem, paths);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Detect ecosystem markers under a project directory without walking the full
|
|
183
|
+
* tree: the directory itself is inspected, then up to
|
|
184
|
+
* {@link MAX_SUBDIRS_SCANNED} immediate subdirectories in sorted order. Paths
|
|
185
|
+
* are built with `node:path`, so `markersOnDisk` carries platform-correct
|
|
186
|
+
* separators.
|
|
187
|
+
*
|
|
188
|
+
* @param {string} projectPath Directory that was scanned, when known.
|
|
189
|
+
* @param {Object} [hooks] Test hooks.
|
|
190
|
+
* @param {(dirPath: string) => {name: string, directory: boolean}[]} [hooks.listDir] Directory lister override.
|
|
191
|
+
* @returns {{markersByEcosystem: Map<string, string[]>, scannedDirectories: number}} Marker paths per ecosystem and the number of directories inspected.
|
|
192
|
+
*/
|
|
193
|
+
export function detectEcosystemMarkers(projectPath, hooks = {}) {
|
|
194
|
+
const markersByEcosystem = new Map();
|
|
195
|
+
if (!projectPath || !safeExistsSync(projectPath)) {
|
|
196
|
+
return { markersByEcosystem, scannedDirectories: 0 };
|
|
197
|
+
}
|
|
198
|
+
const listDir = hooks.listDir || listDirectory;
|
|
199
|
+
let rootEntries;
|
|
200
|
+
try {
|
|
201
|
+
rootEntries = listDir(projectPath);
|
|
202
|
+
} catch {
|
|
203
|
+
return { markersByEcosystem, scannedDirectories: 0 };
|
|
204
|
+
}
|
|
205
|
+
scanEntries(projectPath, rootEntries, markersByEcosystem);
|
|
206
|
+
const subdirs = rootEntries
|
|
207
|
+
.filter((entry) => entry.directory)
|
|
208
|
+
.map((entry) => entry.name)
|
|
209
|
+
.slice(0, MAX_SUBDIRS_SCANNED);
|
|
210
|
+
let scannedDirectories = 1;
|
|
211
|
+
for (const subdir of subdirs) {
|
|
212
|
+
const subdirPath = join(projectPath, subdir);
|
|
213
|
+
try {
|
|
214
|
+
scanEntries(subdirPath, listDir(subdirPath), markersByEcosystem);
|
|
215
|
+
} catch {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
scannedDirectories += 1;
|
|
219
|
+
}
|
|
220
|
+
const sorted = new Map(
|
|
221
|
+
[...markersByEcosystem.entries()].map(([ecosystem, paths]) => [
|
|
222
|
+
ecosystem,
|
|
223
|
+
[...paths].sort(),
|
|
224
|
+
]),
|
|
225
|
+
);
|
|
226
|
+
return { markersByEcosystem: sorted, scannedDirectories };
|
|
227
|
+
}
|