@cdxgen/cdxgen 13.4.0 → 13.5.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 +7 -7
- package/bin/cdxgen-secure.js +15 -0
- package/bin/cdxgen.js +25 -5
- package/bin/evinse.js +5 -0
- package/bin/hbom.js +15 -7
- package/bin/repl.js +29 -0
- package/data/cbomosdb-queries.json +13 -1
- package/data/component-tags.json +8 -0
- package/data/queries-darwin.json +25 -1
- package/data/queries-win.json +19 -1
- package/data/queries.json +41 -0
- package/data/remediations.json +283 -1
- package/data/rules/cbom-security.yaml +235 -4
- package/data/rules/go-binaries.yaml +46 -0
- package/data/rules/golem-go.yaml +80 -0
- package/data/rules/hbom-compliance.yaml +40 -22
- package/data/rules/hbom-performance.yaml +7 -1
- package/data/rules/host-topology.yaml +1 -1
- package/data/rules/obom-runtime.yaml +31 -2
- package/data/rules/php-runtime.yaml +143 -0
- package/lib/audit/index.js +14 -0
- package/lib/cli/bomAssembly.js +28 -3
- package/lib/cli/cliOptions.js +110 -3
- package/lib/cli/index.js +73 -4
- package/lib/cli/jvmBom.js +126 -20
- package/lib/cli/managedBom.js +711 -71
- package/lib/cli/nativeBom.js +225 -28
- package/lib/core/env.js +30 -8
- package/lib/core/fs.js +28 -19
- package/lib/core/httpClient.js +74 -45
- package/lib/core/projectConfig.js +1 -0
- package/lib/core/projectTooling.js +97 -0
- package/lib/core/propertySanitizer.js +72 -0
- package/lib/ecosystems/golem.js +550 -6
- package/lib/ecosystems/gradleutils.js +30 -20
- package/lib/ecosystems/parsers-dotnet.js +117 -18
- package/lib/ecosystems/parsers-go.js +1090 -367
- package/lib/ecosystems/parsers-jvm.js +259 -17
- package/lib/ecosystems/parsers-misc.js +229 -44
- package/lib/ecosystems/parsers-python.js +11 -10
- package/lib/ecosystems/rubyutils.js +6 -3
- package/lib/ecosystems/rusi.js +10 -0
- package/lib/ecosystems/scalacliutils.js +2 -1
- package/lib/ecosystems/scalasem.js +3 -1
- package/lib/evinser/evinser.js +126 -18
- package/lib/evinser/swiftsem.js +68 -5
- package/lib/inventory/agentSkillSpec.js +17 -0
- package/lib/inventory/apkInstalledDb.js +243 -0
- package/lib/inventory/atomUtils.js +33 -0
- package/lib/inventory/auditCategories.js +3 -3
- package/lib/inventory/cacheDir.js +52 -9
- package/lib/inventory/certificates.js +2371 -0
- package/lib/inventory/communityAiConfigParser.js +4 -9
- package/lib/inventory/deps.js +6 -4
- package/lib/inventory/display.js +200 -3
- package/lib/inventory/dosai.js +500 -58
- package/lib/inventory/dynamic.js +45 -3
- package/lib/inventory/envcontext.js +168 -5
- package/lib/inventory/evidenceUtils.js +436 -23
- package/lib/inventory/formulationParsers.js +3 -2
- package/lib/inventory/goBuildInfo.js +140 -0
- package/lib/inventory/hbom.js +67 -7
- package/lib/inventory/hbomAnalysis.js +16 -0
- package/lib/inventory/hostTopology.js +21 -0
- package/lib/inventory/osPackagePurl.js +244 -0
- package/lib/inventory/osPackageResolver.js +89 -87
- package/lib/inventory/osinfo.js +79 -31
- package/lib/inventory/osqueryTransform.js +114 -5
- package/lib/inventory/phpBuildInfo.js +487 -0
- package/lib/inventory/phpHostProbe.js +641 -0
- package/lib/inventory/rootfsCerts.js +426 -0
- package/lib/inventory/source.js +207 -3
- package/lib/inventory/spdx.js +144 -0
- package/lib/inventory/traceRunner.js +5 -1
- package/lib/inventory/tracedCrypto.js +129 -0
- package/lib/managers/binary.js +529 -183
- package/lib/managers/docker.js +166 -12
- package/lib/parsers/email.js +277 -0
- package/lib/parsers/largeJson.js +34 -2
- package/lib/server/server.js +186 -1
- package/lib/stages/postgen/annotator.js +17 -1
- package/lib/stages/postgen/introspection/reflect.js +4 -1
- package/lib/stages/postgen/postgen.js +5 -5
- package/lib/stages/postgen/ruleEngine.js +58 -1
- package/lib/stages/postgen/specVersionCompat.js +30 -0
- package/lib/stages/pregen/pregen.js +117 -5
- package/lib/validator/bomValidator.js +26 -5
- package/lib/validator/generated/runtime.mjs +13 -0
- package/lib/validator/generated/validate-1.6.mjs +26 -7
- package/lib/validator/generated/validate-1.7.mjs +31 -12
- package/lib/validator/generated/validate-2.0.mjs +30 -11
- package/package.json +17 -17
- package/types/bin/cdxgen-secure.d.ts +3 -0
- package/types/bin/cdxgen-secure.d.ts.map +1 -0
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/cli/bomAssembly.d.ts +9 -2
- package/types/lib/cli/bomAssembly.d.ts.map +1 -1
- package/types/lib/cli/cliOptions.d.ts +43 -0
- package/types/lib/cli/cliOptions.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/cli/jvmBom.d.ts +20 -0
- 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/env.d.ts +18 -2
- package/types/lib/core/env.d.ts.map +1 -1
- package/types/lib/core/fs.d.ts.map +1 -1
- package/types/lib/core/httpClient.d.ts.map +1 -1
- package/types/lib/core/projectConfig.d.ts.map +1 -1
- package/types/lib/core/projectTooling.d.ts +41 -0
- package/types/lib/core/projectTooling.d.ts.map +1 -0
- package/types/lib/core/propertySanitizer.d.ts +26 -0
- package/types/lib/core/propertySanitizer.d.ts.map +1 -1
- package/types/lib/ecosystems/cppEvidence.d.ts +1 -1
- package/types/lib/ecosystems/golem.d.ts +81 -1
- package/types/lib/ecosystems/golem.d.ts.map +1 -1
- package/types/lib/ecosystems/gradleutils.d.ts +10 -8
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-dotnet.d.ts +40 -4
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-go.d.ts +85 -13
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-jvm.d.ts +28 -2
- package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-misc.d.ts +18 -58
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -1
- package/types/lib/ecosystems/parsers-python.d.ts +4 -3
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -1
- package/types/lib/ecosystems/pythonutils.d.ts +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/ecosystems/scalacliutils.d.ts.map +1 -1
- package/types/lib/ecosystems/scalasem.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +25 -0
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/evinser/swiftsem.d.ts +10 -0
- package/types/lib/evinser/swiftsem.d.ts.map +1 -1
- package/types/lib/inventory/agentSkillSpec.d.ts +13 -0
- package/types/lib/inventory/agentSkillSpec.d.ts.map +1 -0
- package/types/lib/inventory/apkInstalledDb.d.ts +42 -0
- package/types/lib/inventory/apkInstalledDb.d.ts.map +1 -0
- package/types/lib/inventory/atomUtils.d.ts +14 -0
- package/types/lib/inventory/atomUtils.d.ts.map +1 -1
- package/types/lib/inventory/cacheDir.d.ts +12 -4
- package/types/lib/inventory/cacheDir.d.ts.map +1 -1
- package/types/lib/inventory/certificates.d.ts +205 -0
- package/types/lib/inventory/certificates.d.ts.map +1 -0
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/inventory/deps.d.ts +2 -1
- package/types/lib/inventory/deps.d.ts.map +1 -1
- package/types/lib/inventory/display.d.ts +18 -0
- package/types/lib/inventory/display.d.ts.map +1 -1
- package/types/lib/inventory/dosai.d.ts +145 -6
- package/types/lib/inventory/dosai.d.ts.map +1 -1
- package/types/lib/inventory/dynamic.d.ts +6 -1
- package/types/lib/inventory/dynamic.d.ts.map +1 -1
- package/types/lib/inventory/envcontext.d.ts +40 -2
- package/types/lib/inventory/envcontext.d.ts.map +1 -1
- package/types/lib/inventory/evidenceUtils.d.ts +29 -10
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -1
- package/types/lib/inventory/formulationParsers.d.ts.map +1 -1
- package/types/lib/inventory/goBuildInfo.d.ts +10 -0
- package/types/lib/inventory/goBuildInfo.d.ts.map +1 -0
- package/types/lib/inventory/hbom.d.ts.map +1 -1
- package/types/lib/inventory/hbomAnalysis.d.ts +10 -0
- package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -1
- package/types/lib/inventory/hostTopology.d.ts.map +1 -1
- package/types/lib/inventory/osPackagePurl.d.ts +99 -0
- package/types/lib/inventory/osPackagePurl.d.ts.map +1 -0
- package/types/lib/inventory/osPackageResolver.d.ts +6 -2
- package/types/lib/inventory/osPackageResolver.d.ts.map +1 -1
- package/types/lib/inventory/osinfo.d.ts +31 -6
- package/types/lib/inventory/osinfo.d.ts.map +1 -1
- package/types/lib/inventory/osqueryTransform.d.ts +51 -0
- package/types/lib/inventory/osqueryTransform.d.ts.map +1 -1
- package/types/lib/inventory/phpBuildInfo.d.ts +142 -0
- package/types/lib/inventory/phpBuildInfo.d.ts.map +1 -0
- package/types/lib/inventory/phpHostProbe.d.ts +35 -0
- package/types/lib/inventory/phpHostProbe.d.ts.map +1 -0
- package/types/lib/inventory/rootfsCerts.d.ts +27 -0
- package/types/lib/inventory/rootfsCerts.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts +28 -0
- package/types/lib/inventory/source.d.ts.map +1 -1
- package/types/lib/inventory/spdx.d.ts +15 -0
- package/types/lib/inventory/spdx.d.ts.map +1 -1
- package/types/lib/inventory/traceRunner.d.ts +4 -1
- package/types/lib/inventory/traceRunner.d.ts.map +1 -1
- package/types/lib/inventory/tracedCrypto.d.ts +22 -0
- package/types/lib/inventory/tracedCrypto.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +10 -0
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +12 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/parsers/email.d.ts +19 -0
- package/types/lib/parsers/email.d.ts.map +1 -0
- package/types/lib/parsers/largeJson.d.ts +13 -0
- package/types/lib/parsers/largeJson.d.ts.map +1 -1
- package/types/lib/server/server.d.ts +8 -0
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
- package/types/lib/stages/postgen/introspection/reflect.d.ts.map +1 -1
- package/types/lib/stages/postgen/ruleEngine.d.ts +7 -4
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -1
- package/types/lib/stages/pregen/pregen.d.ts +14 -1
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -1
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { readFileSync, realpathSync } from "node:fs";
|
|
2
2
|
import { join, relative } from "node:path";
|
|
3
3
|
|
|
4
|
-
import { build } from "@cdxgen/cdx-purl";
|
|
5
4
|
import { globSync } from "glob";
|
|
6
5
|
|
|
7
6
|
import { DEBUG_MODE, recordSymlinkResolution } from "../core/activity.js";
|
|
8
7
|
import { safeExistsSync, safeSpawnSync } from "../core/fs.js";
|
|
9
8
|
import { thoughtLog } from "../core/logger.js";
|
|
10
9
|
import { getDistroInfo } from "./osinfo.js";
|
|
10
|
+
import { buildOsPackagePurl } from "./osPackagePurl.js";
|
|
11
11
|
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
// Caches
|
|
@@ -48,58 +48,34 @@ function parseAlpinePackage(pkgStr) {
|
|
|
48
48
|
// ---------------------------------------------------------------------------
|
|
49
49
|
// Build a PackageURL string from resolved package info.
|
|
50
50
|
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
51
|
+
// deb, rpm, apk and Homebrew packages are named by buildOsPackagePurl, the
|
|
52
|
+
// function the OBOM rows use as well, so a file and the package that owns it
|
|
53
|
+
// share one identity with the package an OBOM or a container scan lists. The
|
|
54
|
+
// distro qualifiers come from /etc/os-release via getDistroInfo(), never from
|
|
55
|
+
// a hard-coded table.
|
|
53
56
|
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
57
|
+
// Homebrew has no official purl type yet, but cdx-purl builds pkg:brew, as the
|
|
58
|
+
// OBOM does for its homebrew_packages rows. A brew purl carries no qualifiers:
|
|
59
|
+
// this used to pass an `arch` that the generic type it fell back to does not
|
|
60
|
+
// allow, so build() threw and a file of a Homebrew package got no purl at all.
|
|
56
61
|
// ---------------------------------------------------------------------------
|
|
57
62
|
function buildPurl(pkgInfo) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (pkgInfo.arch) {
|
|
63
|
-
qualifiers.arch = pkgInfo.arch;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (purlType === "deb" || purlType === "apk" || purlType === "rpm") {
|
|
67
|
-
const di = getDistroInfo();
|
|
68
|
-
namespace = di.namespace;
|
|
69
|
-
|
|
70
|
-
// distro qualifier: ID-VERSION_ID (e.g. "fedora-25", "alpine-3.17")
|
|
71
|
-
if (di.distroId) {
|
|
72
|
-
qualifiers.distro = di.distroId;
|
|
73
|
-
}
|
|
74
|
-
// distro_name qualifier: codename (e.g. "jammy", "bookworm")
|
|
75
|
-
if (di.distroName) {
|
|
76
|
-
qualifiers.distro_name = di.distroName;
|
|
77
|
-
}
|
|
78
|
-
} else if (purlType === "brew") {
|
|
79
|
-
// No official brew purl type — fall back to generic. This used to add a
|
|
80
|
-
// `package_manager=homebrew` qualifier, which generic does not allow, so
|
|
81
|
-
// build() threw and the catch below swallowed it: Homebrew packages silently
|
|
82
|
-
// received no purl at all on macOS. The provenance is instead recorded as a
|
|
83
|
-
// property by the caller.
|
|
84
|
-
purlType = "generic";
|
|
85
|
-
}
|
|
63
|
+
const distro =
|
|
64
|
+
pkgInfo.type === "brew" || !pkgInfo.type ? undefined : getDistroInfo();
|
|
65
|
+
return buildOsPackagePurl(pkgInfo, distro) || "";
|
|
66
|
+
}
|
|
86
67
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
68
|
+
// apk names an architecture its own way, which is not the way node does.
|
|
69
|
+
const APK_ARCHITECTURES = {
|
|
70
|
+
x64: "x86_64",
|
|
71
|
+
arm64: "aarch64",
|
|
72
|
+
ia32: "x86",
|
|
73
|
+
ppc64: "ppc64le",
|
|
74
|
+
loong64: "loongarch64",
|
|
75
|
+
};
|
|
90
76
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
type: purlType,
|
|
94
|
-
namespace: namespace || undefined || null,
|
|
95
|
-
name: pkgInfo.name,
|
|
96
|
-
version: pkgInfo.version || undefined || null,
|
|
97
|
-
qualifiers: finalQualifiers || null,
|
|
98
|
-
subpath: undefined || null,
|
|
99
|
-
});
|
|
100
|
-
} catch (_e) {
|
|
101
|
-
return "";
|
|
102
|
-
}
|
|
77
|
+
function apkArchitecture() {
|
|
78
|
+
return APK_ARCHITECTURES[process.arch] || process.arch;
|
|
103
79
|
}
|
|
104
80
|
|
|
105
81
|
// ---------------------------------------------------------------------------
|
|
@@ -111,7 +87,7 @@ function buildPurl(pkgInfo) {
|
|
|
111
87
|
* correctly computed purl with distro qualifiers derived from /etc/os-release.
|
|
112
88
|
*
|
|
113
89
|
* @param {string} filePath - Absolute path to the library file
|
|
114
|
-
* @returns {{ name: string, version: string, arch: string, type: string, purl: string } | undefined}
|
|
90
|
+
* @returns {{ name: string, version: string, arch: string, type: string, epoch?: string, purl: string } | undefined}
|
|
115
91
|
*/
|
|
116
92
|
export function resolvePackageForFile(filePath) {
|
|
117
93
|
if (!filePath) {
|
|
@@ -190,27 +166,30 @@ function _resolveLinux(filePath) {
|
|
|
190
166
|
return {
|
|
191
167
|
name,
|
|
192
168
|
version,
|
|
193
|
-
arch:
|
|
169
|
+
arch: apkArchitecture(),
|
|
194
170
|
type: "apk",
|
|
195
171
|
};
|
|
196
172
|
}
|
|
197
173
|
}
|
|
198
174
|
|
|
199
|
-
// 3. RPM-based (rpm -qf)
|
|
175
|
+
// 3. RPM-based (rpm -qf). The epoch is part of an rpm's identity; %{EPOCH} is
|
|
176
|
+
// (none) for a package without one, so the conditional makes that a 0, which
|
|
177
|
+
// means the same.
|
|
200
178
|
const rpmRes = safeSpawnSync("rpm", [
|
|
201
179
|
"-qf",
|
|
202
180
|
"--qf",
|
|
203
|
-
"%{NAME} %{VERSION}-%{RELEASE} %{ARCH}\n",
|
|
181
|
+
"%{NAME} %|EPOCH?{%{EPOCH}}:{0}| %{VERSION}-%{RELEASE} %{ARCH}\n",
|
|
204
182
|
filePath,
|
|
205
183
|
]);
|
|
206
184
|
if (rpmRes && rpmRes.status === 0 && rpmRes.stdout) {
|
|
207
185
|
const line = rpmRes.stdout.split("\n")[0].trim();
|
|
208
186
|
const parts = line.split(" ");
|
|
209
|
-
if (parts.length >=
|
|
187
|
+
if (parts.length >= 4) {
|
|
210
188
|
return {
|
|
211
189
|
name: parts[0],
|
|
212
|
-
|
|
213
|
-
|
|
190
|
+
epoch: parts[1],
|
|
191
|
+
version: parts[2],
|
|
192
|
+
arch: parts[3],
|
|
214
193
|
type: "rpm",
|
|
215
194
|
};
|
|
216
195
|
}
|
|
@@ -233,7 +212,7 @@ function _resolveDarwin(filePath) {
|
|
|
233
212
|
name: segments[0],
|
|
234
213
|
version: segments[1],
|
|
235
214
|
arch: process.arch,
|
|
236
|
-
type: "brew",
|
|
215
|
+
type: "brew",
|
|
237
216
|
};
|
|
238
217
|
}
|
|
239
218
|
}
|
|
@@ -379,6 +358,9 @@ function shouldPreferUsrMergedExecutablePath(file, existingFile) {
|
|
|
379
358
|
* @param ldConf {String} Config file used by ldconfig to locate additional paths
|
|
380
359
|
* @param ldConfDirPattern {String} Config directory that can contain more .conf files for ldconfig
|
|
381
360
|
* @param excludePaths {Array[String]} Container-relative paths that should be excluded from the result set
|
|
361
|
+
* @param extraLibGlobs {Array[String]} Extra container-relative globs for files
|
|
362
|
+
* the default paths miss, such as libphp*.so under Apache's modules
|
|
363
|
+
* directory. The existing globs are unchanged; this adds candidates only.
|
|
382
364
|
*
|
|
383
365
|
* @return {Array[String]} List of executables
|
|
384
366
|
*/
|
|
@@ -388,6 +370,7 @@ export function collectSharedLibs(
|
|
|
388
370
|
ldConf,
|
|
389
371
|
ldConfDirPattern,
|
|
390
372
|
excludePaths = [],
|
|
373
|
+
extraLibGlobs = [],
|
|
391
374
|
) {
|
|
392
375
|
if (!libPaths) {
|
|
393
376
|
return [];
|
|
@@ -399,6 +382,37 @@ export function collectSharedLibs(
|
|
|
399
382
|
const ignoreList = [
|
|
400
383
|
"**/*.{h,c,cpp,hpp,man,txt,md,htm,html,jar,ear,war,zip,tar,egg,keepme,gitignore,json,js,py,pyc}",
|
|
401
384
|
];
|
|
385
|
+
const addCandidate = (file) => {
|
|
386
|
+
let resolvedFile = file;
|
|
387
|
+
try {
|
|
388
|
+
resolvedFile = relative(basePath, realpathSync(join(basePath, file)));
|
|
389
|
+
recordSymlinkResolution(join(basePath, file), resolvedFile, {
|
|
390
|
+
basePath,
|
|
391
|
+
metadata: {
|
|
392
|
+
resolutionKind: "shared-library",
|
|
393
|
+
},
|
|
394
|
+
reason: `Resolved shared library candidate ${file} to ${resolvedFile}.`,
|
|
395
|
+
});
|
|
396
|
+
} catch (err) {
|
|
397
|
+
recordSymlinkResolution(join(basePath, file), undefined, {
|
|
398
|
+
basePath,
|
|
399
|
+
errorCode: err?.code || err?.name,
|
|
400
|
+
metadata: {
|
|
401
|
+
resolutionKind: "shared-library",
|
|
402
|
+
},
|
|
403
|
+
reason: `Failed to resolve shared library candidate ${file}.`,
|
|
404
|
+
status: "failed",
|
|
405
|
+
});
|
|
406
|
+
// Broken symlinks or permission errors can prevent realpath resolution.
|
|
407
|
+
}
|
|
408
|
+
if (
|
|
409
|
+
excludedPathSet.has(file.replace(/^\/+/, "").replace(/\\/g, "/")) ||
|
|
410
|
+
excludedPathSet.has(resolvedFile.replace(/^\/+/, "").replace(/\\/g, "/"))
|
|
411
|
+
) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
sharedLibs.push(file);
|
|
415
|
+
};
|
|
402
416
|
const allLdConfDirs = ldConfDirPattern ? [ldConfDirPattern] : [];
|
|
403
417
|
collectAllLdConfs(basePath, ldConf, allLdConfDirs, libPaths);
|
|
404
418
|
if (allLdConfDirs.length) {
|
|
@@ -428,37 +442,25 @@ export function collectSharedLibs(
|
|
|
428
442
|
ignore: ignoreList,
|
|
429
443
|
});
|
|
430
444
|
for (const file of files) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
});
|
|
451
|
-
// Broken symlinks or permission errors can prevent realpath resolution.
|
|
452
|
-
}
|
|
453
|
-
if (
|
|
454
|
-
excludedPathSet.has(file.replace(/^\/+/, "").replace(/\\/g, "/")) ||
|
|
455
|
-
excludedPathSet.has(
|
|
456
|
-
resolvedFile.replace(/^\/+/, "").replace(/\\/g, "/"),
|
|
457
|
-
)
|
|
458
|
-
) {
|
|
459
|
-
continue;
|
|
460
|
-
}
|
|
461
|
-
sharedLibs.push(file);
|
|
445
|
+
addCandidate(file);
|
|
446
|
+
}
|
|
447
|
+
} catch (_err) {
|
|
448
|
+
// ignore
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
for (const pattern of extraLibGlobs) {
|
|
452
|
+
try {
|
|
453
|
+
const files = globSync(pattern, {
|
|
454
|
+
cwd: basePath,
|
|
455
|
+
absolute: false,
|
|
456
|
+
nocase: true,
|
|
457
|
+
nodir: true,
|
|
458
|
+
dot: true,
|
|
459
|
+
follow: true,
|
|
460
|
+
ignore: ignoreList,
|
|
461
|
+
});
|
|
462
|
+
for (const file of files) {
|
|
463
|
+
addCandidate(file);
|
|
462
464
|
}
|
|
463
465
|
} catch (_err) {
|
|
464
466
|
// ignore
|
package/lib/inventory/osinfo.js
CHANGED
|
@@ -49,14 +49,34 @@ export const OS_DISTRO_ALIAS = {
|
|
|
49
49
|
"ubuntu-24.10": "oracular",
|
|
50
50
|
"ubuntu-25.04": "plucky",
|
|
51
51
|
"ubuntu-25.10": "questing",
|
|
52
|
+
"ubuntu-26.04": "resolute",
|
|
53
|
+
"ubuntu-26.10": "stonking",
|
|
52
54
|
"debian-15": "duke",
|
|
53
55
|
"debian-14": "forky",
|
|
54
56
|
"debian-14.5": "forky",
|
|
55
57
|
"debian-13": "trixie",
|
|
58
|
+
"debian-13.7": "trixie",
|
|
59
|
+
"debian-13.6": "trixie",
|
|
56
60
|
"debian-13.5": "trixie",
|
|
61
|
+
"debian-13.4": "trixie",
|
|
62
|
+
"debian-13.3": "trixie",
|
|
63
|
+
"debian-13.2": "trixie",
|
|
64
|
+
"debian-13.1": "trixie",
|
|
57
65
|
"debian-12": "bookworm",
|
|
58
|
-
"debian-12.
|
|
66
|
+
"debian-12.15": "bookworm",
|
|
67
|
+
"debian-12.14": "bookworm",
|
|
68
|
+
"debian-12.13": "bookworm",
|
|
69
|
+
"debian-12.12": "bookworm",
|
|
70
|
+
"debian-12.11": "bookworm",
|
|
71
|
+
"debian-12.10": "bookworm",
|
|
72
|
+
"debian-12.9": "bookworm",
|
|
73
|
+
"debian-12.8": "bookworm",
|
|
74
|
+
"debian-12.7": "bookworm",
|
|
59
75
|
"debian-12.6": "bookworm",
|
|
76
|
+
"debian-12.5": "bookworm",
|
|
77
|
+
"debian-12.4": "bookworm",
|
|
78
|
+
"debian-12.2": "bookworm",
|
|
79
|
+
"debian-12.1": "bookworm",
|
|
60
80
|
"debian-11": "bullseye",
|
|
61
81
|
"debian-11.5": "bullseye",
|
|
62
82
|
"debian-10": "buster",
|
|
@@ -256,15 +276,20 @@ export function _resetOsReleaseCache() {
|
|
|
256
276
|
* Derive structured distro information from an os-release file.
|
|
257
277
|
*
|
|
258
278
|
* Returns an object with:
|
|
259
|
-
* - purlType {string} "deb" | "apk" | "rpm"
|
|
279
|
+
* - purlType {string} "deb" | "apk" | "rpm" | "alpm" (Arch and the
|
|
280
|
+
* distros built on it)
|
|
260
281
|
* - namespace {string} canonical purl namespace (e.g. "ubuntu", "alpine",
|
|
261
282
|
* "azure-linux" for both Azure Linux and CBL-Mariner)
|
|
262
283
|
* - distroId {string} ID + "-" + VERSION_ID with a canonical vendor
|
|
263
|
-
* prefix (e.g. "ubuntu-22.04", "azure-linux-3.0"
|
|
264
|
-
*
|
|
284
|
+
* prefix (e.g. "ubuntu-22.04", "azure-linux-3.0",
|
|
285
|
+
* "alpine-3.24.3")
|
|
286
|
+
* - distroName {string} release codename, or a token OS_DISTRO_ALIAS knows
|
|
287
|
+
* (e.g. "jammy", "rhel", "alpine-3.24"); empty when
|
|
288
|
+
* the distro has neither
|
|
265
289
|
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
290
|
+
* lib/managers/binary.js getOSPackages() reads its distro from here, so a
|
|
291
|
+
* container scan and an OBOM run on the same system give a package the same
|
|
292
|
+
* `distro` and `distro_name` qualifiers.
|
|
268
293
|
*
|
|
269
294
|
* @param {string} [root="/"] - Filesystem root to look for os-release.
|
|
270
295
|
* @returns {{ purlType: string, namespace: string, distroId: string, distroName: string }}
|
|
@@ -290,6 +315,8 @@ export function getDistroInfo(root = "/") {
|
|
|
290
315
|
case "alpine":
|
|
291
316
|
case "alpaquita":
|
|
292
317
|
case "openwrt":
|
|
318
|
+
case "wolfi":
|
|
319
|
+
case "chainguard":
|
|
293
320
|
purlType = "apk";
|
|
294
321
|
break;
|
|
295
322
|
case "sles":
|
|
@@ -312,11 +339,23 @@ export function getDistroInfo(root = "/") {
|
|
|
312
339
|
case "photon":
|
|
313
340
|
purlType = "rpm";
|
|
314
341
|
break;
|
|
342
|
+
case "arch":
|
|
343
|
+
case "archarm":
|
|
344
|
+
case "manjaro":
|
|
345
|
+
case "endeavouros":
|
|
346
|
+
case "cachyos":
|
|
347
|
+
case "steamos":
|
|
348
|
+
case "artix":
|
|
349
|
+
purlType = "alpm";
|
|
350
|
+
break;
|
|
315
351
|
default:
|
|
316
352
|
if (idLike.includes("debian") || idLike.includes("ubuntu")) {
|
|
317
353
|
purlType = "deb";
|
|
318
354
|
} else if (idLike.includes("alpine")) {
|
|
319
355
|
purlType = "apk";
|
|
356
|
+
} else if (idLike.split(/\s+/u).includes("arch")) {
|
|
357
|
+
// A token, not a substring: ID_LIKE is a space-separated list.
|
|
358
|
+
purlType = "alpm";
|
|
320
359
|
} else if (
|
|
321
360
|
idLike.includes("rhel") ||
|
|
322
361
|
idLike.includes("centos") ||
|
|
@@ -343,41 +382,50 @@ export function getDistroInfo(root = "/") {
|
|
|
343
382
|
namespace = "debian";
|
|
344
383
|
} else if (idLike.includes("ubuntu")) {
|
|
345
384
|
namespace = "ubuntu";
|
|
385
|
+
} else if (purlType === "alpm") {
|
|
386
|
+
namespace = "arch";
|
|
346
387
|
} else {
|
|
347
388
|
namespace = "linux";
|
|
348
389
|
}
|
|
349
390
|
}
|
|
350
391
|
|
|
351
|
-
// Build distroId = ID-VERSION_ID (e.g. "fedora-25",
|
|
352
|
-
// canonicalising the vendor prefix so one release has a
|
|
353
|
-
// value (e.g. "mariner-2.0" and "azurelinux-3.0" ->
|
|
354
|
-
// "azure-linux-3.0")
|
|
355
|
-
|
|
356
|
-
distroId = canonicalDistroQualifier(
|
|
392
|
+
// Build distroId = ID-VERSION_ID as os-release writes it (e.g. "fedora-25",
|
|
393
|
+
// "alpine-3.24.3"), canonicalising the vendor prefix so one release has a
|
|
394
|
+
// single qualifier value (e.g. "mariner-2.0" and "azurelinux-3.0" ->
|
|
395
|
+
// "azure-linux-2.0"/"azure-linux-3.0")
|
|
396
|
+
const releaseId = versionId ? `${rawId}-${versionId}` : rawId;
|
|
397
|
+
const distroId = canonicalDistroQualifier(releaseId);
|
|
357
398
|
|
|
358
|
-
//
|
|
359
|
-
|
|
399
|
+
// distro_name is a release codename or a token OS_DISTRO_ALIAS knows
|
|
400
|
+
// ("bookworm", "jammy", "rhel", "alpine-3.24"), never a product display
|
|
401
|
+
// name: "AlmaLinux" or "Rocky Linux 9" has no place in a purl, since RPM
|
|
402
|
+
// distros track packages flat and a display name there breaks vulnerability
|
|
403
|
+
// matching. A product name counts only when it resolves through the alias
|
|
404
|
+
// table, which holds the RHEL names.
|
|
405
|
+
let distroName = (info.VERSION_CODENAME || "").toLowerCase();
|
|
406
|
+
if (!distroName) {
|
|
407
|
+
const productName = (
|
|
408
|
+
info.CENTOS_MANTISBT_PROJECT ||
|
|
409
|
+
info.REDHAT_BUGZILLA_PRODUCT ||
|
|
410
|
+
info.REDHAT_SUPPORT_PRODUCT ||
|
|
411
|
+
""
|
|
412
|
+
).toLowerCase();
|
|
413
|
+
if (productName && Object.hasOwn(OS_DISTRO_ALIAS, productName)) {
|
|
414
|
+
distroName = OS_DISTRO_ALIAS[productName];
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
// Alpine names its release series: 3.24.3 belongs to alpine-3.24, the unit
|
|
418
|
+
// its security data is kept in.
|
|
419
|
+
if (rawId === "alpine" && versionId) {
|
|
360
420
|
const parts = versionId.split(".");
|
|
361
421
|
if (parts.length >= 2) {
|
|
362
|
-
|
|
422
|
+
distroName = `alpine-${parts[0]}.${parts[1]}`;
|
|
363
423
|
}
|
|
364
424
|
}
|
|
365
|
-
|
|
366
|
-
//
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
info.CENTOS_MANTISBT_PROJECT ||
|
|
370
|
-
info.REDHAT_BUGZILLA_PRODUCT ||
|
|
371
|
-
info.REDHAT_SUPPORT_PRODUCT ||
|
|
372
|
-
"";
|
|
373
|
-
distroName = distroName.toLowerCase();
|
|
374
|
-
|
|
375
|
-
// Resolve well-known display name aliases
|
|
376
|
-
if (distroName.includes(" ") && OS_DISTRO_ALIAS[distroName]) {
|
|
377
|
-
distroName = OS_DISTRO_ALIAS[distroName];
|
|
378
|
-
}
|
|
379
|
-
if (!distroName && OS_DISTRO_ALIAS[distroId]) {
|
|
380
|
-
distroName = OS_DISTRO_ALIAS[distroId];
|
|
425
|
+
// The alias of the release itself (ubuntu-24.04 -> noble) wins over the
|
|
426
|
+
// codename the file carries.
|
|
427
|
+
if (versionId && Object.hasOwn(OS_DISTRO_ALIAS, releaseId)) {
|
|
428
|
+
distroName = OS_DISTRO_ALIAS[releaseId];
|
|
381
429
|
}
|
|
382
430
|
|
|
383
431
|
return { purlType, namespace, distroId, distroName };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getDistroInfo } from "./osinfo.js";
|
|
2
|
+
import { buildOsPackagePurl, osPackageVersion } from "./osPackagePurl.js";
|
|
2
3
|
import { tryBuildPurl } from "./purl.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -62,6 +63,8 @@ export function deriveOsQueryPublisher(res) {
|
|
|
62
63
|
res.creator ||
|
|
63
64
|
res.manufacturer ||
|
|
64
65
|
res.provider ||
|
|
66
|
+
res.packager ||
|
|
67
|
+
res.developer_name ||
|
|
65
68
|
"";
|
|
66
69
|
return publisher === "null" ? "" : publisher;
|
|
67
70
|
}
|
|
@@ -174,7 +177,10 @@ export function shouldCreateOsQueryPurl(componentType) {
|
|
|
174
177
|
|
|
175
178
|
// Purl types whose type rules require a namespace. For OS package types the
|
|
176
179
|
// namespace is the distro vendor (`pkg:deb/debian/...`, `pkg:rpm/redhat/...`),
|
|
177
|
-
// which osquery does not report but /etc/os-release does.
|
|
180
|
+
// which osquery does not report but /etc/os-release does. deb, rpm and apk rows
|
|
181
|
+
// are named by createOsQueryPackageIdentity; this covers the other types that
|
|
182
|
+
// need a vendor (portage's ebuild) and a caller that asks for one of the three
|
|
183
|
+
// directly.
|
|
178
184
|
const NAMESPACE_REQUIRED_TYPES = new Set([
|
|
179
185
|
"deb",
|
|
180
186
|
"rpm",
|
|
@@ -216,10 +222,9 @@ export function createOsQueryPurl(
|
|
|
216
222
|
if (type === "swid" && !finalQualifiers.tag_id) {
|
|
217
223
|
finalQualifiers.tag_id = name;
|
|
218
224
|
}
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
// purl instead of losing one.
|
|
225
|
+
// Rows with no group whose purl type requires a namespace get the vendor from
|
|
226
|
+
// /etc/os-release, the way osPackageResolver does, so they keep a valid purl
|
|
227
|
+
// instead of losing one.
|
|
223
228
|
let namespace = group || null;
|
|
224
229
|
if (!namespace && NAMESPACE_REQUIRED_TYPES.has(type)) {
|
|
225
230
|
namespace = getDistroInfo().namespace || null;
|
|
@@ -237,6 +242,110 @@ export function createOsQueryPurl(
|
|
|
237
242
|
});
|
|
238
243
|
}
|
|
239
244
|
|
|
245
|
+
/**
|
|
246
|
+
* The version and purl of a row from an OS package table: `deb_packages`,
|
|
247
|
+
* `rpm_packages`, `pacman_packages`, `homebrew_packages`, `macports_packages`,
|
|
248
|
+
* `snap_packages`, `flatpak_packages` or the rows of the apk database.
|
|
249
|
+
*
|
|
250
|
+
* Such a row is named the way the package manager's own scan names it: deb,
|
|
251
|
+
* rpm and apk with the vendor and the `arch`, `distro`, `distro_name` and
|
|
252
|
+
* `epoch` qualifiers of the container scan, an rpm version joined to its
|
|
253
|
+
* release, a MacPorts version joined to its revision, a flatpak by its
|
|
254
|
+
* application ID with the `arch` and `branch` of its ref. A row's `path`,
|
|
255
|
+
* `admindir` or source file is not a path inside the package, so none of them
|
|
256
|
+
* becomes a subpath.
|
|
257
|
+
*
|
|
258
|
+
* @param {string} purlType One of OS_PACKAGE_PURL_TYPES
|
|
259
|
+
* @param {Object} res osquery row
|
|
260
|
+
* @param {string} name Component name derived from the row
|
|
261
|
+
* @param {Object} [distro] What getDistroInfo() reports; the host's by default
|
|
262
|
+
* @returns {{version: string, purl: string|null}} The component version and the purl, which is null when the row cannot be expressed as one
|
|
263
|
+
*/
|
|
264
|
+
export function createOsQueryPackageIdentity(purlType, res, name, distro) {
|
|
265
|
+
const pkg = {
|
|
266
|
+
type: purlType,
|
|
267
|
+
name,
|
|
268
|
+
version: res.version,
|
|
269
|
+
arch: res.arch,
|
|
270
|
+
};
|
|
271
|
+
if (purlType === "rpm") {
|
|
272
|
+
pkg.release = res.release;
|
|
273
|
+
pkg.epoch = res.epoch;
|
|
274
|
+
} else if (purlType === "macports") {
|
|
275
|
+
pkg.revision = res.revision;
|
|
276
|
+
} else if (purlType === "flatpak") {
|
|
277
|
+
pkg.branch = res.branch;
|
|
278
|
+
}
|
|
279
|
+
return {
|
|
280
|
+
version: osPackageVersion(pkg),
|
|
281
|
+
purl: buildOsPackagePurl(pkg, distro),
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Columns of an OS package table that are named or dropped on their way to a
|
|
286
|
+
// property. A bare `source` is the source package of a deb, the source rpm file
|
|
287
|
+
// of an rpm and the pkgbase of a pacman package, and `type` says whether a
|
|
288
|
+
// Homebrew entry is a formula or a cask, a snap an app or a base, a flatpak an
|
|
289
|
+
// app or a runtime, so each takes the name that says which. The dpkg
|
|
290
|
+
// administrative directory and the pacman database path are the same for every
|
|
291
|
+
// package and say nothing about one.
|
|
292
|
+
const OS_PACKAGE_PROPERTY_NAMES = {
|
|
293
|
+
deb: { source: "cdx:deb:source", admindir: undefined },
|
|
294
|
+
rpm: { source: "cdx:rpm:sourceRpm" },
|
|
295
|
+
apk: { origin: "cdx:apk:origin" },
|
|
296
|
+
alpm: { source: "cdx:alpm:pkgbase", dbpath: undefined },
|
|
297
|
+
brew: { type: "cdx:homebrew:type" },
|
|
298
|
+
macports: {
|
|
299
|
+
variants: "cdx:macports:variants",
|
|
300
|
+
requested: "cdx:macports:requested",
|
|
301
|
+
},
|
|
302
|
+
snap: {
|
|
303
|
+
type: "cdx:snap:type",
|
|
304
|
+
revision: "cdx:snap:revision",
|
|
305
|
+
channel: "cdx:snap:channel",
|
|
306
|
+
confinement: "cdx:snap:confinement",
|
|
307
|
+
},
|
|
308
|
+
flatpak: {
|
|
309
|
+
display_name: "cdx:flatpak:displayName",
|
|
310
|
+
commit_hash: "cdx:flatpak:commit",
|
|
311
|
+
origin: "cdx:flatpak:origin",
|
|
312
|
+
installation: "cdx:flatpak:installation",
|
|
313
|
+
type: "cdx:flatpak:type",
|
|
314
|
+
runtime: "cdx:flatpak:runtime",
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* The columns of an OS package row that give its licence and its home page.
|
|
320
|
+
* They become the component's `licenses` and a `website` reference rather than
|
|
321
|
+
* properties. `separator` splits a licence column that lists several: pacman
|
|
322
|
+
* keeps one licence per entry, which osquery joins with commas.
|
|
323
|
+
*/
|
|
324
|
+
export const OS_PACKAGE_LICENSE_COLUMNS = {
|
|
325
|
+
alpm: { license: "licenses", separator: ",", website: "url" },
|
|
326
|
+
snap: { license: "license" },
|
|
327
|
+
flatpak: { license: "license", website: "homepage" },
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* The property name an OS package table column is emitted under.
|
|
332
|
+
*
|
|
333
|
+
* @param {string|undefined} purlType Purl type of the table
|
|
334
|
+
* @param {string} column Column name
|
|
335
|
+
* @returns {string|undefined} The property name, or undefined when the column is not emitted
|
|
336
|
+
*/
|
|
337
|
+
export function osPackagePropertyName(purlType, column) {
|
|
338
|
+
const fields = OS_PACKAGE_LICENSE_COLUMNS[purlType];
|
|
339
|
+
if (fields && (column === fields.license || column === fields.website)) {
|
|
340
|
+
return undefined;
|
|
341
|
+
}
|
|
342
|
+
const names = OS_PACKAGE_PROPERTY_NAMES[purlType];
|
|
343
|
+
if (names && Object.hasOwn(names, column)) {
|
|
344
|
+
return names[column];
|
|
345
|
+
}
|
|
346
|
+
return column;
|
|
347
|
+
}
|
|
348
|
+
|
|
240
349
|
function _deriveCertificateFormat(certificateFileExtension) {
|
|
241
350
|
switch ((certificateFileExtension || "").toLowerCase()) {
|
|
242
351
|
case "pem":
|