@cdxgen/cdxgen 13.0.0 → 13.0.1
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 +4 -4
- package/bin/cdxgen.js +15 -4
- package/bin/convert.js +7 -0
- package/bin/hbom.js +13 -4
- package/bin/tracebom.js +9 -1
- package/lib/cli/bomAssembly.js +64 -15
- package/lib/cli/cliOptions.js +30 -0
- package/lib/core/logger.js +153 -15
- package/lib/core/ui.js +46 -2
- package/lib/ecosystems/utils.js +9 -1
- package/lib/inventory/envcontext.js +5 -1
- package/lib/inventory/osinfo.js +122 -16
- package/lib/inventory/table.js +9 -5
- package/lib/managers/binary.js +192 -40
- package/package.json +12 -12
- package/types/lib/cli/bomAssembly.d.ts +14 -0
- package/types/lib/cli/bomAssembly.d.ts.map +1 -1
- package/types/lib/cli/cliOptions.d.ts.map +1 -1
- package/types/lib/core/logger.d.ts +23 -1
- package/types/lib/core/logger.d.ts.map +1 -1
- package/types/lib/core/ui.d.ts +1 -1
- package/types/lib/core/ui.d.ts.map +1 -1
- package/types/lib/ecosystems/utils.d.ts +4 -4
- package/types/lib/ecosystems/utils.d.ts.map +1 -1
- package/types/lib/inventory/envcontext.d.ts.map +1 -1
- package/types/lib/inventory/osinfo.d.ts +83 -2
- package/types/lib/inventory/osinfo.d.ts.map +1 -1
- package/types/lib/inventory/table.d.ts +4 -1
- package/types/lib/inventory/table.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +71 -0
- package/types/lib/managers/binary.d.ts.map +1 -1
package/lib/ecosystems/utils.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Deprecated re-export barrel.
|
|
3
3
|
*
|
|
4
|
-
* `utils.js` declares nothing of its own. It re-exports
|
|
4
|
+
* `utils.js` declares nothing of its own. It re-exports every public name that
|
|
5
5
|
* used to live here so existing imports keep working for one major version. Each
|
|
6
6
|
* implementation, and its JSDoc, now lives in the leaf module it was moved to
|
|
7
7
|
* (`purl.js`, `spdx.js`, `deps.js`, `ecosystems.js`, `parsers-*.js`, `core-*.js`,
|
|
@@ -191,11 +191,13 @@ import {
|
|
|
191
191
|
import { getMavenCommand, getMillCommand } from "./gradleutils.js";
|
|
192
192
|
import { createNpmWorkspacePurl } from "./npmutils.js";
|
|
193
193
|
import {
|
|
194
|
+
getCentralPackageVersions,
|
|
194
195
|
getPropertyGroupTextNodes,
|
|
195
196
|
parseCsPkgData,
|
|
196
197
|
parseCsPkgLockData,
|
|
197
198
|
parseCsProjAssetsData,
|
|
198
199
|
parseCsProjData,
|
|
200
|
+
parseDirectoryPackagesProps,
|
|
199
201
|
parseNupkg,
|
|
200
202
|
parseNuspecData,
|
|
201
203
|
parsePaketLockData,
|
|
@@ -220,12 +222,14 @@ import {
|
|
|
220
222
|
parsePackageJsonName,
|
|
221
223
|
parsePkgJson,
|
|
222
224
|
parsePkgLock,
|
|
225
|
+
parsePnpmAliasRef,
|
|
223
226
|
parsePnpmLock,
|
|
224
227
|
parsePnpmWorkspace,
|
|
225
228
|
parseYarnLock,
|
|
226
229
|
parseYarnWorkspace,
|
|
227
230
|
pnpmMetadata,
|
|
228
231
|
splitCommandArgs,
|
|
232
|
+
stripPnpmPeerSuffix,
|
|
229
233
|
yarnLockToIdentMap,
|
|
230
234
|
} from "./parsers-js.js";
|
|
231
235
|
import {
|
|
@@ -369,6 +373,7 @@ export {
|
|
|
369
373
|
getAllFiles,
|
|
370
374
|
getAllFilesWithIgnore,
|
|
371
375
|
getAtomCommand,
|
|
376
|
+
getCentralPackageVersions,
|
|
372
377
|
getCratesMetadata,
|
|
373
378
|
getDartMetadata,
|
|
374
379
|
getDefaultBomAuditCategories,
|
|
@@ -465,6 +470,7 @@ export {
|
|
|
465
470
|
parseCsProjAssetsData,
|
|
466
471
|
parseCsProjData,
|
|
467
472
|
parseCUsageSlice,
|
|
473
|
+
parseDirectoryPackagesProps,
|
|
468
474
|
parseEdnData,
|
|
469
475
|
parseFlakeLock,
|
|
470
476
|
parseFlakeNix,
|
|
@@ -503,6 +509,7 @@ export {
|
|
|
503
509
|
parsePixiTomlFile,
|
|
504
510
|
parsePkgJson,
|
|
505
511
|
parsePkgLock,
|
|
512
|
+
parsePnpmAliasRef,
|
|
506
513
|
parsePnpmLock,
|
|
507
514
|
parsePnpmWorkspace,
|
|
508
515
|
parsePodfileLock,
|
|
@@ -565,6 +572,7 @@ export {
|
|
|
565
572
|
shouldFetchVCS,
|
|
566
573
|
shouldRunPredictiveBomAudit,
|
|
567
574
|
splitCommandArgs,
|
|
575
|
+
stripPnpmPeerSuffix,
|
|
568
576
|
TABLE_BORDER_STYLE,
|
|
569
577
|
TIMEOUT_MS,
|
|
570
578
|
toCamel,
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
safeExistsSync,
|
|
32
32
|
safeSpawnSync,
|
|
33
33
|
} from "../core/fs.js";
|
|
34
|
+
import { diagnosticStream } from "../core/logger.js";
|
|
34
35
|
import { dirNameStr, isMac, isWin } from "../core/paths.js";
|
|
35
36
|
import { applyPurl, tryBuildPurl } from "./purl.js";
|
|
36
37
|
|
|
@@ -919,9 +920,12 @@ export function bundleInstallWithDocker(rubyVersion, cdxgenGemHome, filePath) {
|
|
|
919
920
|
"install",
|
|
920
921
|
];
|
|
921
922
|
console.log(`Performing bundle install with: ${ociCmd}`);
|
|
923
|
+
// The container's own output is a diagnostic. Inheriting stdout would let it
|
|
924
|
+
// interleave with the BOM document when the caller asked for `-o -`, so the
|
|
925
|
+
// child's stdout is pointed at the diagnostic stream instead.
|
|
922
926
|
const result = safeSpawnSync(ociCmd, ociArgs, {
|
|
923
927
|
shell: isWin,
|
|
924
|
-
stdio: "inherit",
|
|
928
|
+
stdio: ["inherit", diagnosticStream, "inherit"],
|
|
925
929
|
});
|
|
926
930
|
if (result.error || result.status !== 0) {
|
|
927
931
|
return false;
|
package/lib/inventory/osinfo.js
CHANGED
|
@@ -86,6 +86,112 @@ export const OS_DISTRO_ALIAS = {
|
|
|
86
86
|
"red hat enterprise linux 10": "rhel-10",
|
|
87
87
|
};
|
|
88
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Canonical purl namespace for distro vendors that are published under more
|
|
91
|
+
* than one spelling. Both the os-release path (`getDistroInfo`) and the trivy
|
|
92
|
+
* passthrough in `lib/managers/binary.js` route through this single map so the
|
|
93
|
+
* two paths cannot drift apart again.
|
|
94
|
+
*
|
|
95
|
+
* Azure Linux 2.0 is CBL-Mariner 2.0 — Microsoft renamed the product — and the
|
|
96
|
+
* OSV feed publishes `pkg:rpm/azure-linux/<name>` for every generation
|
|
97
|
+
* (ecosystems "Azure Linux:2" and "Azure Linux:3"), so the historical
|
|
98
|
+
* spellings azurelinux, cbl-mariner and mariner all canonicalise to
|
|
99
|
+
* "azure-linux". rhel/ol/amzn/opensuse-* are the cases previously inlined in
|
|
100
|
+
* getDistroInfo(); alma/rocky-linux were previously inlined in binary.js.
|
|
101
|
+
*
|
|
102
|
+
* Amazon Linux canonicalises to "amazon", the spelling the vulnerability feeds
|
|
103
|
+
* publish (AppThreat vuln-list `amazon`): the os-release ID is `amzn` and
|
|
104
|
+
* trivy emits `amazon`, and the previous `amazonlinux` mapping here matched
|
|
105
|
+
* neither, so live-host Amazon Linux purls matched nothing at all.
|
|
106
|
+
*/
|
|
107
|
+
export const OS_NAMESPACE_ALIAS = {
|
|
108
|
+
alma: "almalinux",
|
|
109
|
+
amazonlinux: "amazon",
|
|
110
|
+
amzn: "amazon",
|
|
111
|
+
azurelinux: "azure-linux",
|
|
112
|
+
"cbl-mariner": "azure-linux",
|
|
113
|
+
mariner: "azure-linux",
|
|
114
|
+
ol: "oracle",
|
|
115
|
+
"opensuse-leap": "opensuse",
|
|
116
|
+
"opensuse-tumbleweed": "opensuse",
|
|
117
|
+
rhel: "redhat",
|
|
118
|
+
"rocky-linux": "rocky",
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Vendor prefixes that `distro` qualifier values are canonicalised for, so one
|
|
123
|
+
* release has exactly one qualifier value no matter which side produced it.
|
|
124
|
+
*
|
|
125
|
+
* trivy stamps the qualifier from its own distro table while cdxgen stamps it
|
|
126
|
+
* from os-release, and the two disagree: an Oracle Linux 9.8 image came out
|
|
127
|
+
* with `oracle-9.8` on 99 components and `ol-9.8` on 43, and a RHEL 9.8 image
|
|
128
|
+
* with namespace `redhat` but qualifier `rhel-9.8`. Canonicalising both sides
|
|
129
|
+
* through this map collapses each release onto the vendor its purl namespace
|
|
130
|
+
* already uses.
|
|
131
|
+
*
|
|
132
|
+
* SUSE is deliberately absent. `sles-15.6`, `opensuse-leap-15.6` and
|
|
133
|
+
* `opensuse-tumbleweed-<snapshot>` are the values consumers derive the release
|
|
134
|
+
* channel from (vulnerability-db maps them to per-release channels), and both
|
|
135
|
+
* sides already agree on them; folding Leap and Tumbleweed onto a bare
|
|
136
|
+
* `opensuse-` vendor would destroy exactly the distinction that matters.
|
|
137
|
+
*
|
|
138
|
+
* Keys are matched longest-first so `cbl-mariner-2.0` resolves against the
|
|
139
|
+
* full vendor segment rather than a shorter prefix.
|
|
140
|
+
*/
|
|
141
|
+
export const OS_DISTRO_QUALIFIER_ALIAS = {
|
|
142
|
+
alma: "almalinux",
|
|
143
|
+
amazonlinux: "amazon",
|
|
144
|
+
amzn: "amazon",
|
|
145
|
+
azurelinux: "azure-linux",
|
|
146
|
+
"cbl-mariner": "azure-linux",
|
|
147
|
+
mariner: "azure-linux",
|
|
148
|
+
ol: "oracle",
|
|
149
|
+
rhel: "redhat",
|
|
150
|
+
"rocky-linux": "rocky",
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// A distro qualifier reaches a purl verbatim, so anything outside the purl
|
|
154
|
+
// qualifier charset makes the whole purl — and with it the whole BOM —
|
|
155
|
+
// invalid. trivy emits Amazon Linux as
|
|
156
|
+
// `amazon-2023.12.20260727+(Amazon Linux)`, which failed cdxgen's own schema
|
|
157
|
+
// validation and cost the entire SBOM.
|
|
158
|
+
const SAFE_DISTRO_QUALIFIER = /^[A-Za-z0-9._-]+$/;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Whether a `distro` qualifier value is safe to place in a purl unencoded.
|
|
162
|
+
*
|
|
163
|
+
* @param {string} qualifier - distro qualifier value
|
|
164
|
+
* @returns {boolean} true when the value contains only purl-safe characters
|
|
165
|
+
*/
|
|
166
|
+
export function isCleanDistroQualifier(qualifier) {
|
|
167
|
+
return !!qualifier && SAFE_DISTRO_QUALIFIER.test(qualifier);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const OS_DISTRO_QUALIFIER_ALIAS_KEYS = Object.keys(
|
|
171
|
+
OS_DISTRO_QUALIFIER_ALIAS,
|
|
172
|
+
).sort((a, b) => b.length - a.length);
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Canonicalise the vendor prefix of a `distro` qualifier value
|
|
176
|
+
* (e.g. "cbl-mariner-2.0" or "mariner-2.0" -> "azure-linux-2.0") so a release
|
|
177
|
+
* has exactly one qualifier spelling regardless of which tool emitted it.
|
|
178
|
+
* Values without a known vendor prefix are returned unchanged.
|
|
179
|
+
*
|
|
180
|
+
* @param {string} qualifier - distro qualifier value such as "azurelinux-3.0"
|
|
181
|
+
* @returns {string} canonical qualifier value
|
|
182
|
+
*/
|
|
183
|
+
export function canonicalDistroQualifier(qualifier) {
|
|
184
|
+
if (!qualifier) {
|
|
185
|
+
return qualifier;
|
|
186
|
+
}
|
|
187
|
+
for (const key of OS_DISTRO_QUALIFIER_ALIAS_KEYS) {
|
|
188
|
+
if (qualifier.startsWith(`${key}-`)) {
|
|
189
|
+
return `${OS_DISTRO_QUALIFIER_ALIAS[key]}${qualifier.slice(key.length)}`;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return qualifier;
|
|
193
|
+
}
|
|
194
|
+
|
|
89
195
|
// ---------------------------------------------------------------------------
|
|
90
196
|
// Raw os-release cache — keyed by the osRelease file path so the live-host
|
|
91
197
|
// cache (/etc/os-release) and any container rootfs path are kept separate.
|
|
@@ -151,8 +257,10 @@ export function _resetOsReleaseCache() {
|
|
|
151
257
|
*
|
|
152
258
|
* Returns an object with:
|
|
153
259
|
* - purlType {string} "deb" | "apk" | "rpm"
|
|
154
|
-
* - namespace {string} purl namespace (e.g. "ubuntu", "alpine",
|
|
155
|
-
*
|
|
260
|
+
* - namespace {string} canonical purl namespace (e.g. "ubuntu", "alpine",
|
|
261
|
+
* "azure-linux" for both Azure Linux and CBL-Mariner)
|
|
262
|
+
* - distroId {string} ID + "-" + VERSION_ID with a canonical vendor
|
|
263
|
+
* prefix (e.g. "ubuntu-22.04", "azure-linux-3.0")
|
|
156
264
|
* - distroName {string} codename/alias (e.g. "jammy")
|
|
157
265
|
*
|
|
158
266
|
* Mirrors the logic in lib/managers/binary.js getOSPackages() so that both
|
|
@@ -193,6 +301,9 @@ export function getDistroInfo(root = "/") {
|
|
|
193
301
|
case "centos":
|
|
194
302
|
case "rocky":
|
|
195
303
|
case "almalinux":
|
|
304
|
+
case "azurelinux":
|
|
305
|
+
case "cbl-mariner":
|
|
306
|
+
case "mariner":
|
|
196
307
|
case "oracle":
|
|
197
308
|
case "ol":
|
|
198
309
|
case "amzn":
|
|
@@ -216,19 +327,10 @@ export function getDistroInfo(root = "/") {
|
|
|
216
327
|
break;
|
|
217
328
|
}
|
|
218
329
|
|
|
219
|
-
// Determine the purl namespace (vendor)
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
} else if (rawId === "ol") {
|
|
224
|
-
namespace = "oracle";
|
|
225
|
-
} else if (rawId === "amzn") {
|
|
226
|
-
namespace = "amazonlinux";
|
|
227
|
-
} else if (rawId === "opensuse-leap" || rawId === "opensuse-tumbleweed") {
|
|
228
|
-
namespace = "opensuse";
|
|
229
|
-
} else if (rawId === "almalinux") {
|
|
230
|
-
namespace = "almalinux";
|
|
231
|
-
} else if (!rawId) {
|
|
330
|
+
// Determine the purl namespace (vendor), canonicalising vendors that are
|
|
331
|
+
// published under several spellings (e.g. mariner -> azure-linux)
|
|
332
|
+
let namespace = OS_NAMESPACE_ALIAS[rawId] || rawId;
|
|
333
|
+
if (!rawId) {
|
|
232
334
|
// Fallback via ID_LIKE
|
|
233
335
|
if (idLike.includes("rhel") || idLike.includes("centos")) {
|
|
234
336
|
namespace = "redhat";
|
|
@@ -245,8 +347,12 @@ export function getDistroInfo(root = "/") {
|
|
|
245
347
|
}
|
|
246
348
|
}
|
|
247
349
|
|
|
248
|
-
// Build distroId = ID-VERSION_ID (e.g. "fedora-25", "alpine-3.17")
|
|
350
|
+
// Build distroId = ID-VERSION_ID (e.g. "fedora-25", "alpine-3.17"),
|
|
351
|
+
// canonicalising the vendor prefix so one release has a single qualifier
|
|
352
|
+
// value (e.g. "mariner-2.0" and "azurelinux-3.0" -> "azure-linux-2.0"/
|
|
353
|
+
// "azure-linux-3.0")
|
|
249
354
|
let distroId = versionId ? `${rawId}-${versionId}` : rawId;
|
|
355
|
+
distroId = canonicalDistroQualifier(distroId);
|
|
250
356
|
|
|
251
357
|
// Special-case Alpine: truncate to major.minor
|
|
252
358
|
if (purlType === "apk" && versionId) {
|
package/lib/inventory/table.js
CHANGED
|
@@ -2,6 +2,7 @@ import process from "node:process";
|
|
|
2
2
|
|
|
3
3
|
import { readEnvironmentVariable } from "../core/activity.js";
|
|
4
4
|
import { TABLE_BORDER_STYLE } from "../core/env.js";
|
|
5
|
+
import { diagnosticStream } from "../core/logger.js";
|
|
5
6
|
import {
|
|
6
7
|
alignText,
|
|
7
8
|
stringWidth,
|
|
@@ -218,7 +219,10 @@ export function table(rows, config = {}) {
|
|
|
218
219
|
}
|
|
219
220
|
|
|
220
221
|
/**
|
|
221
|
-
* Create a streaming table writer that renders rows
|
|
222
|
+
* Create a streaming table writer that renders rows incrementally.
|
|
223
|
+
*
|
|
224
|
+
* Rows go to the diagnostic stream: a rendered table is human-readable output,
|
|
225
|
+
* and writing it to stdout corrupted the BOM document under `-o -`.
|
|
222
226
|
*
|
|
223
227
|
* @param {Object} [config={}] Table configuration (header, columns, border style)
|
|
224
228
|
* @returns {{write(row: *): void, end(): void}} Writer whose `end()` emits the bottom border
|
|
@@ -242,21 +246,21 @@ export function createStream(config = {}) {
|
|
|
242
246
|
const topBorder = drawBorder(columns, borderChars, "top");
|
|
243
247
|
middleBorder = drawBorder(columns, borderChars, "mid");
|
|
244
248
|
bottomBorder = drawBorder(columns, borderChars, "bottom");
|
|
245
|
-
|
|
249
|
+
diagnosticStream.write(`${topBorder}\n`);
|
|
246
250
|
}
|
|
247
251
|
if (hasRows) {
|
|
248
|
-
|
|
252
|
+
diagnosticStream.write(`${middleBorder}\n`);
|
|
249
253
|
}
|
|
250
254
|
const safeRow = Array.isArray(row) ? row : [row];
|
|
251
255
|
const rendered = renderRow(safeRow, columns, borderChars);
|
|
252
|
-
|
|
256
|
+
diagnosticStream.write(`${rendered.join("\n")}\n`);
|
|
253
257
|
hasRows = true;
|
|
254
258
|
},
|
|
255
259
|
end() {
|
|
256
260
|
if (!columns || closed) {
|
|
257
261
|
return;
|
|
258
262
|
}
|
|
259
|
-
|
|
263
|
+
diagnosticStream.write(`${bottomBorder}\n`);
|
|
260
264
|
closed = true;
|
|
261
265
|
},
|
|
262
266
|
};
|
package/lib/managers/binary.js
CHANGED
|
@@ -37,7 +37,13 @@ import {
|
|
|
37
37
|
extractToolRefs,
|
|
38
38
|
} from "../inventory/evidenceUtils.js";
|
|
39
39
|
import { createGtfoBinsProperties } from "../inventory/gtfobins.js";
|
|
40
|
-
import {
|
|
40
|
+
import {
|
|
41
|
+
canonicalDistroQualifier,
|
|
42
|
+
isCleanDistroQualifier,
|
|
43
|
+
OS_DISTRO_ALIAS,
|
|
44
|
+
OS_NAMESPACE_ALIAS,
|
|
45
|
+
readOsRelease,
|
|
46
|
+
} from "../inventory/osinfo.js";
|
|
41
47
|
import {
|
|
42
48
|
collectExecutables,
|
|
43
49
|
collectSharedLibs,
|
|
@@ -57,13 +63,6 @@ import { getDirs } from "./containerutils.js";
|
|
|
57
63
|
|
|
58
64
|
const isWin = _platform() === "win32";
|
|
59
65
|
const OS_PURL_TYPES = ["deb", "apk", "rpm", "alpm", "qpkg"];
|
|
60
|
-
// Canonical distro vendor namespace. Trivy emits pkg:rpm/alma/... but the
|
|
61
|
-
// vulnerability feeds (AppThreat vuln-list / dep-scan) key AlmaLinux under
|
|
62
|
-
// "almalinux"; align so the purls match. Rocky is emitted as "rocky" already.
|
|
63
|
-
const OS_DISTRO_NAMESPACE_ALIAS = {
|
|
64
|
-
alma: "almalinux",
|
|
65
|
-
"rocky-linux": "rocky",
|
|
66
|
-
};
|
|
67
66
|
const pluginRuntime = setPluginsPathEnv(resolveCdxgenPlugins());
|
|
68
67
|
const platform = pluginRuntime.platform;
|
|
69
68
|
const CDXGEN_PLUGINS_DIR = pluginRuntime.pluginsDir;
|
|
@@ -555,6 +554,173 @@ export function executeSourcekitten(args) {
|
|
|
555
554
|
return undefined;
|
|
556
555
|
}
|
|
557
556
|
|
|
557
|
+
/**
|
|
558
|
+
* Canonicalise the distro vendor namespace of an OS package component
|
|
559
|
+
* produced by trivy, regardless of whether trivy expressed the vendor via the
|
|
560
|
+
* purl namespace or the component group (it is inconsistent between
|
|
561
|
+
* packages). e.g. pkg:rpm/alma/... -> pkg:rpm/almalinux/... and
|
|
562
|
+
* pkg:rpm/cbl-mariner/... -> pkg:rpm/azure-linux/... so the purls match the
|
|
563
|
+
* vulnerability feeds. Also aligns the ``distro`` qualifier vendor prefix
|
|
564
|
+
* (alma-9.8 -> almalinux-9.8, mariner-2.0 -> azure-linux-2.0), including
|
|
565
|
+
* spellings that disagree with the namespace, and rebuilds ``group`` and
|
|
566
|
+
* ``bom-ref`` from the rewritten purl.
|
|
567
|
+
*
|
|
568
|
+
* The namespace table is OS_NAMESPACE_ALIAS from lib/inventory/osinfo.js so
|
|
569
|
+
* the trivy path and the os-release path (getDistroInfo) cannot drift apart.
|
|
570
|
+
*
|
|
571
|
+
* A `distro` qualifier that is not purl-safe (trivy emits Amazon Linux as
|
|
572
|
+
* `amazon-2023.12.20260727+(Amazon Linux)`) is replaced with the os-release
|
|
573
|
+
* derived value, or dropped when there is none: an unusable qualifier
|
|
574
|
+
* invalidates the purl and fails validation for the whole BOM.
|
|
575
|
+
*
|
|
576
|
+
* @param {Object} comp trivy OS package component (mutated in place)
|
|
577
|
+
* @param {Object} purlObj parsed PackageURL of comp.purl (mutated in place)
|
|
578
|
+
* @param {string} name component package name (basename form)
|
|
579
|
+
* @param {string} group component group derived from the trivy component name
|
|
580
|
+
* @param {string} [distroId] canonical os-release distro id, e.g. "amazon-2023"
|
|
581
|
+
* @returns {string} the canonicalised group
|
|
582
|
+
*/
|
|
583
|
+
export function canonicaliseOsPackageNamespace(
|
|
584
|
+
comp,
|
|
585
|
+
purlObj,
|
|
586
|
+
name,
|
|
587
|
+
group,
|
|
588
|
+
distroId,
|
|
589
|
+
) {
|
|
590
|
+
if (!purlObj || !OS_PURL_TYPES.includes(purlObj.type)) {
|
|
591
|
+
return group;
|
|
592
|
+
}
|
|
593
|
+
const os_ns = purlObj.namespace || group || "";
|
|
594
|
+
const os_ns_alias = OS_NAMESPACE_ALIAS[os_ns];
|
|
595
|
+
const distroQual = purlObj.qualifiers?.distro;
|
|
596
|
+
let canonicalDistroQual = distroQual;
|
|
597
|
+
if (os_ns_alias && distroQual?.startsWith(`${os_ns}-`)) {
|
|
598
|
+
canonicalDistroQual = `${os_ns_alias}-${distroQual.slice(os_ns.length + 1)}`;
|
|
599
|
+
}
|
|
600
|
+
canonicalDistroQual = canonicalDistroQualifier(canonicalDistroQual);
|
|
601
|
+
if (canonicalDistroQual && !isCleanDistroQualifier(canonicalDistroQual)) {
|
|
602
|
+
canonicalDistroQual = isCleanDistroQualifier(distroId)
|
|
603
|
+
? distroId
|
|
604
|
+
: undefined;
|
|
605
|
+
}
|
|
606
|
+
if (!os_ns_alias && canonicalDistroQual === distroQual) {
|
|
607
|
+
return group;
|
|
608
|
+
}
|
|
609
|
+
group = os_ns_alias || purlObj.namespace || group || "";
|
|
610
|
+
comp.group = group;
|
|
611
|
+
purlObj.namespace = group;
|
|
612
|
+
if (canonicalDistroQual !== distroQual) {
|
|
613
|
+
if (canonicalDistroQual) {
|
|
614
|
+
purlObj.qualifiers.distro = canonicalDistroQual;
|
|
615
|
+
} else {
|
|
616
|
+
delete purlObj.qualifiers.distro;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
comp.purl = build({
|
|
620
|
+
type: purlObj.type,
|
|
621
|
+
namespace: purlObj.namespace || null,
|
|
622
|
+
name: name,
|
|
623
|
+
version: purlObj.version || null,
|
|
624
|
+
qualifiers: purlObj.qualifiers || null,
|
|
625
|
+
subpath: purlObj.subpath || null,
|
|
626
|
+
});
|
|
627
|
+
comp["bom-ref"] = decodeURIComponent(comp.purl);
|
|
628
|
+
return group;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Repair a `distro` qualifier that cannot survive purl parsing, in place.
|
|
633
|
+
*
|
|
634
|
+
* trivy stamps Amazon Linux with the full pretty version — the qualifier
|
|
635
|
+
* arrives as `distro=amazon-2023.12.20260727+%28Amazon+Linux%29`, whose spaces
|
|
636
|
+
* and parentheses `Purl.parse` rejects outright ("Invalid character in
|
|
637
|
+
* qualifier distro"). The component then bypasses every canonicalisation below
|
|
638
|
+
* (they all need a parsed purl) and reaches the BOM verbatim, where schema
|
|
639
|
+
* validation fails and the *entire* SBOM is discarded — an Amazon Linux scan
|
|
640
|
+
* produces no output at all today.
|
|
641
|
+
*
|
|
642
|
+
* The release is already known from os-release, so the unusable value is
|
|
643
|
+
* swapped for it; with no usable replacement the qualifier is dropped, since a
|
|
644
|
+
* missing qualifier costs one matching hint while an invalid one costs the
|
|
645
|
+
* whole document.
|
|
646
|
+
*
|
|
647
|
+
* @param {Object} comp component whose purl may carry an unusable qualifier
|
|
648
|
+
* @param {string} [distroId] canonical os-release distro id, e.g. "amazon-2023"
|
|
649
|
+
* @returns {Object} the same component
|
|
650
|
+
*/
|
|
651
|
+
export function repairOsComponentPurl(comp, distroId) {
|
|
652
|
+
const purl = comp?.purl;
|
|
653
|
+
if (!purl?.includes("distro=")) {
|
|
654
|
+
return comp;
|
|
655
|
+
}
|
|
656
|
+
const match = /([?&]distro=)([^&]*)/.exec(purl);
|
|
657
|
+
if (!match) {
|
|
658
|
+
return comp;
|
|
659
|
+
}
|
|
660
|
+
let decoded = match[2];
|
|
661
|
+
try {
|
|
662
|
+
decoded = decodeURIComponent(match[2].replace(/\+/g, " "));
|
|
663
|
+
} catch (_err) {
|
|
664
|
+
// A value that cannot even be decoded is definitely not purl-safe
|
|
665
|
+
}
|
|
666
|
+
if (isCleanDistroQualifier(decoded)) {
|
|
667
|
+
return comp;
|
|
668
|
+
}
|
|
669
|
+
const replacement = isCleanDistroQualifier(distroId)
|
|
670
|
+
? `${match[1]}${distroId}`
|
|
671
|
+
: "";
|
|
672
|
+
comp.purl = purl.replace(match[0], replacement).replace(/\?&/, "?");
|
|
673
|
+
if (comp.purl.endsWith("?")) {
|
|
674
|
+
comp.purl = comp.purl.slice(0, -1);
|
|
675
|
+
}
|
|
676
|
+
comp["bom-ref"] = decodeURIComponent(comp.purl);
|
|
677
|
+
return comp;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Drop source-package shadow components that duplicate a real installed
|
|
682
|
+
* package, in place.
|
|
683
|
+
*
|
|
684
|
+
* A shadow is emitted whenever an rpm/deb declares a source name different
|
|
685
|
+
* from its own (bzip2-libs -> bzip2) so that scanners keying on source names
|
|
686
|
+
* still match. When the source package is *itself* installed at the same
|
|
687
|
+
* version, the shadow's purl is identical to the real component's and the two
|
|
688
|
+
* collapse in trimComponents() — which keeps whichever was seen first and
|
|
689
|
+
* never merges `tags`. Seen-first is trivy's listing order, so the outcome is
|
|
690
|
+
* arbitrary: when the shadow wins, a genuinely installed package is reported
|
|
691
|
+
* with `tags: ["source"]` and identity confidence 0, the very marker the
|
|
692
|
+
* shadow carries so consumers can filter shadows out. That turns a real
|
|
693
|
+
* package into a filtered-away one.
|
|
694
|
+
*
|
|
695
|
+
* Dropping the redundant shadow is loss-free: it duplicates the real
|
|
696
|
+
* component's purl (so nothing that matches on purl changes) and its bom-ref
|
|
697
|
+
* is byte-identical, so no dependency reference can dangle.
|
|
698
|
+
*
|
|
699
|
+
* @param {Array} pkgList component list, mutated in place
|
|
700
|
+
* @returns {Array} the same list, for convenience
|
|
701
|
+
*/
|
|
702
|
+
export function dropRedundantSourceComponents(pkgList) {
|
|
703
|
+
if (!Array.isArray(pkgList) || !pkgList.length) {
|
|
704
|
+
return pkgList;
|
|
705
|
+
}
|
|
706
|
+
const installedPurls = new Set();
|
|
707
|
+
for (const comp of pkgList) {
|
|
708
|
+
if (comp?.purl && !comp?.tags?.includes("source")) {
|
|
709
|
+
installedPurls.add(comp.purl);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
if (!installedPurls.size) {
|
|
713
|
+
return pkgList;
|
|
714
|
+
}
|
|
715
|
+
for (let i = pkgList.length - 1; i >= 0; i--) {
|
|
716
|
+
const comp = pkgList[i];
|
|
717
|
+
if (comp?.tags?.includes("source") && installedPurls.has(comp.purl)) {
|
|
718
|
+
pkgList.splice(i, 1);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
return pkgList;
|
|
722
|
+
}
|
|
723
|
+
|
|
558
724
|
/**
|
|
559
725
|
* Get the packages installed in the container image filesystem.
|
|
560
726
|
*
|
|
@@ -739,6 +905,11 @@ export async function getOSPackages(src, imageConfig, options = {}) {
|
|
|
739
905
|
distro_codename = OS_DISTRO_ALIAS[distro_id];
|
|
740
906
|
}
|
|
741
907
|
}
|
|
908
|
+
// Canonicalise the distro qualifier vendor (e.g. "mariner-2.0" ->
|
|
909
|
+
// "azure-linux-2.0") so every spelling of one release yields a single
|
|
910
|
+
// qualifier value. This runs before distro_id is used to overwrite
|
|
911
|
+
// trivy's own qualifier below.
|
|
912
|
+
distro_id = canonicalDistroQualifier(distro_id);
|
|
742
913
|
const tmpDependencies = {};
|
|
743
914
|
tools = enrichToolComponents(
|
|
744
915
|
(Array.isArray(tmpBom?.metadata?.tools)
|
|
@@ -768,42 +939,23 @@ export async function getOSPackages(src, imageConfig, options = {}) {
|
|
|
768
939
|
comp.group = group;
|
|
769
940
|
comp.name = name;
|
|
770
941
|
const modularityLabel = extractModularityLabel(comp);
|
|
942
|
+
repairOsComponentPurl(comp, distro_id);
|
|
771
943
|
try {
|
|
772
944
|
purlObj = Purl.parse(comp.purl);
|
|
773
945
|
purlObj.qualifiers = purlObj.qualifiers || {};
|
|
774
946
|
} catch (_err) {
|
|
775
947
|
// continue regardless of error
|
|
776
948
|
}
|
|
777
|
-
// Canonicalise the distro vendor namespace
|
|
778
|
-
//
|
|
779
|
-
//
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
group = os_ns_alias;
|
|
788
|
-
comp.group = os_ns_alias;
|
|
789
|
-
purlObj.namespace = os_ns_alias;
|
|
790
|
-
const distroQual = purlObj.qualifiers?.distro;
|
|
791
|
-
if (distroQual?.startsWith(`${os_ns}-`)) {
|
|
792
|
-
purlObj.qualifiers.distro = `${os_ns_alias}-${distroQual.slice(
|
|
793
|
-
os_ns.length + 1,
|
|
794
|
-
)}`;
|
|
795
|
-
}
|
|
796
|
-
comp.purl = build({
|
|
797
|
-
type: purlObj.type,
|
|
798
|
-
namespace: os_ns_alias || null,
|
|
799
|
-
name: name,
|
|
800
|
-
version: purlObj.version || null,
|
|
801
|
-
qualifiers: purlObj.qualifiers || null,
|
|
802
|
-
subpath: purlObj.subpath || null,
|
|
803
|
-
});
|
|
804
|
-
comp["bom-ref"] = decodeURIComponent(comp.purl);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
949
|
+
// Canonicalise the distro vendor namespace (see
|
|
950
|
+
// canonicaliseOsPackageNamespace) before any later bom-ref
|
|
951
|
+
// rebuild so the rewritten purl, group and bom-ref stay in sync.
|
|
952
|
+
group = canonicaliseOsPackageNamespace(
|
|
953
|
+
comp,
|
|
954
|
+
purlObj,
|
|
955
|
+
name,
|
|
956
|
+
group,
|
|
957
|
+
distro_id,
|
|
958
|
+
);
|
|
807
959
|
if (
|
|
808
960
|
group === "" &&
|
|
809
961
|
purlObj &&
|
|
@@ -812,8 +964,7 @@ export async function getOSPackages(src, imageConfig, options = {}) {
|
|
|
812
964
|
try {
|
|
813
965
|
if (purlObj?.namespace && purlObj.namespace !== "") {
|
|
814
966
|
group =
|
|
815
|
-
|
|
816
|
-
purlObj.namespace;
|
|
967
|
+
OS_NAMESPACE_ALIAS[purlObj.namespace] || purlObj.namespace;
|
|
817
968
|
comp.group = group;
|
|
818
969
|
purlObj.namespace = group;
|
|
819
970
|
}
|
|
@@ -1107,6 +1258,7 @@ export async function getOSPackages(src, imageConfig, options = {}) {
|
|
|
1107
1258
|
}
|
|
1108
1259
|
}
|
|
1109
1260
|
}
|
|
1261
|
+
dropRedundantSourceComponents(pkgList);
|
|
1110
1262
|
const rootfsRepositoryInventory = await collectRootfsRepositoryInventory(
|
|
1111
1263
|
src,
|
|
1112
1264
|
options,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdxgen/cdxgen",
|
|
3
|
-
"version": "13.0.
|
|
3
|
+
"version": "13.0.1",
|
|
4
4
|
"description": "Creates CycloneDX Software Bill of Materials (SBOM) from source or container image",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sbom",
|
|
@@ -162,17 +162,17 @@
|
|
|
162
162
|
"@bufbuild/protobuf": "2.13.0",
|
|
163
163
|
"@cdxgen/cdx-hbom": "0.5.1",
|
|
164
164
|
"@cdxgen/cdx-proto": "2.2.0",
|
|
165
|
-
"@cdxgen/cdxgen-plugins-bin": "3.0.
|
|
166
|
-
"@cdxgen/cdxgen-plugins-bin-darwin-amd64": "3.0.
|
|
167
|
-
"@cdxgen/cdxgen-plugins-bin-darwin-arm64": "3.0.
|
|
168
|
-
"@cdxgen/cdxgen-plugins-bin-linux-amd64": "3.0.
|
|
169
|
-
"@cdxgen/cdxgen-plugins-bin-linux-arm": "3.0.
|
|
170
|
-
"@cdxgen/cdxgen-plugins-bin-linux-arm64": "3.0.
|
|
171
|
-
"@cdxgen/cdxgen-plugins-bin-linux-ppc64": "3.0.
|
|
172
|
-
"@cdxgen/cdxgen-plugins-bin-linuxmusl-amd64": "3.0.
|
|
173
|
-
"@cdxgen/cdxgen-plugins-bin-linuxmusl-arm64": "3.0.
|
|
174
|
-
"@cdxgen/cdxgen-plugins-bin-windows-amd64": "3.0.
|
|
175
|
-
"@cdxgen/cdxgen-plugins-bin-windows-arm64": "3.0.
|
|
165
|
+
"@cdxgen/cdxgen-plugins-bin": "3.0.4",
|
|
166
|
+
"@cdxgen/cdxgen-plugins-bin-darwin-amd64": "3.0.4",
|
|
167
|
+
"@cdxgen/cdxgen-plugins-bin-darwin-arm64": "3.0.4",
|
|
168
|
+
"@cdxgen/cdxgen-plugins-bin-linux-amd64": "3.0.4",
|
|
169
|
+
"@cdxgen/cdxgen-plugins-bin-linux-arm": "3.0.4",
|
|
170
|
+
"@cdxgen/cdxgen-plugins-bin-linux-arm64": "3.0.4",
|
|
171
|
+
"@cdxgen/cdxgen-plugins-bin-linux-ppc64": "3.0.4",
|
|
172
|
+
"@cdxgen/cdxgen-plugins-bin-linuxmusl-amd64": "3.0.4",
|
|
173
|
+
"@cdxgen/cdxgen-plugins-bin-linuxmusl-arm64": "3.0.4",
|
|
174
|
+
"@cdxgen/cdxgen-plugins-bin-windows-amd64": "3.0.4",
|
|
175
|
+
"@cdxgen/cdxgen-plugins-bin-windows-arm64": "3.0.4",
|
|
176
176
|
"@cdxgen/safer-exec": "0.15.0",
|
|
177
177
|
"body-parser": "2.3.0",
|
|
178
178
|
"compression": "1.8.1",
|
|
@@ -180,8 +180,22 @@ export declare function determinePackageType(pkg: any): any;
|
|
|
180
180
|
export declare function processHashes(pkg: any, component: any): void;
|
|
181
181
|
/**
|
|
182
182
|
* Adds a hash to component.
|
|
183
|
+
*
|
|
184
|
+
* Registries hand out digests in hex or in the base64 form npm uses for
|
|
185
|
+
* `integrity`, and both are accepted. A digest that is neither, or that decodes
|
|
186
|
+
* to the wrong length for its algorithm, is dropped rather than copied through:
|
|
187
|
+
* CycloneDX constrains `hash.content` to a hex digest, so emitting it anyway
|
|
188
|
+
* fails schema validation for the whole document over one bad package.
|
|
183
189
|
*/
|
|
184
190
|
export declare function addComponentHash(alg: any, digest: any, component: any): void;
|
|
191
|
+
/**
|
|
192
|
+
* Normalize a digest to the lower-case hex form CycloneDX requires.
|
|
193
|
+
*
|
|
194
|
+
* @param {string} alg Hash algorithm name
|
|
195
|
+
* @param {string} digest Digest in hex or base64
|
|
196
|
+
* @returns {string|undefined} Hex digest, or undefined when it cannot be trusted
|
|
197
|
+
*/
|
|
198
|
+
export declare function normalizeHashContent(alg: string, digest: string): string | undefined;
|
|
185
199
|
/**
|
|
186
200
|
* Return the BOM in json format including any namespace mapping
|
|
187
201
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bomAssembly.d.ts","sourceRoot":"","sources":["../../../lib/cli/bomAssembly.js"],"names":[],"mappings":"AA8DA;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,aAJ7B,MAAM,qBACN,MAAM,EAAE,KACN,OAsBZ,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAFf,MAG8E,CAAC;AAEzF;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,0CAH9B,MAAM;;;;;CAwChB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,YAJ1B,MAAM,KACJ,MAAM,GAAC,SAyBnB,CAAC;
|
|
1
|
+
{"version":3,"file":"bomAssembly.d.ts","sourceRoot":"","sources":["../../../lib/cli/bomAssembly.js"],"names":[],"mappings":"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"}
|