@cyclonedx/cdxgen 12.3.2 → 12.4.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 +70 -22
- package/bin/audit.js +21 -7
- package/bin/cdxgen.js +238 -116
- package/bin/convert.js +28 -13
- package/bin/hbom.js +490 -0
- package/bin/repl.js +580 -29
- package/bin/validate.js +34 -4
- package/bin/verify.js +40 -5
- package/data/README.md +298 -25
- package/data/component-tags.json +6 -0
- package/data/crypto-oid.json +16 -0
- package/data/predictive-audit-allowlist.json +11 -0
- package/data/queries-darwin.json +12 -1
- package/data/queries-win.json +7 -1
- package/data/queries.json +39 -2
- package/data/rules/ai-agent-governance.yaml +16 -0
- package/data/rules/asar-archives.yaml +150 -0
- package/data/rules/chrome-extensions.yaml +8 -0
- package/data/rules/ci-permissions.yaml +171 -15
- package/data/rules/container-risk.yaml +14 -7
- package/data/rules/dependency-sources.yaml +76 -5
- package/data/rules/hbom-compliance.yaml +325 -0
- package/data/rules/hbom-performance.yaml +307 -0
- package/data/rules/hbom-security.yaml +248 -0
- package/data/rules/host-topology.yaml +165 -0
- package/data/rules/mcp-servers.yaml +18 -3
- package/data/rules/obom-runtime.yaml +907 -22
- package/data/rules/package-integrity.yaml +36 -0
- package/data/rules/rootfs-hardening.yaml +179 -0
- package/data/rules/vscode-extensions.yaml +9 -0
- package/lib/audit/index.js +209 -8
- package/lib/audit/index.poku.js +332 -0
- package/lib/audit/reporters.js +222 -0
- package/lib/audit/targets.js +146 -1
- package/lib/audit/targets.poku.js +186 -0
- package/lib/cli/asar.poku.js +328 -0
- package/lib/cli/index.js +647 -127
- package/lib/cli/index.poku.js +1905 -187
- package/lib/evinser/evinser.js +14 -9
- package/lib/helpers/agentFormulationParser.js +6 -2
- package/lib/helpers/agentFormulationParser.poku.js +42 -0
- package/lib/helpers/analyzer.js +1444 -38
- package/lib/helpers/analyzer.poku.js +409 -0
- package/lib/helpers/analyzerScope.js +712 -0
- package/lib/helpers/asarutils.js +1556 -0
- package/lib/helpers/asarutils.poku.js +443 -0
- package/lib/helpers/auditCategories.js +12 -0
- package/lib/helpers/auditCategories.poku.js +32 -0
- package/lib/helpers/cbomutils.js +271 -1
- package/lib/helpers/cbomutils.poku.js +248 -5
- package/lib/helpers/chromextutils.js +25 -3
- package/lib/helpers/chromextutils.poku.js +68 -0
- package/lib/helpers/ciParsers/githubActions.js +79 -0
- package/lib/helpers/ciParsers/githubActions.poku.js +103 -0
- package/lib/helpers/communityAiConfigParser.js +15 -5
- package/lib/helpers/communityAiConfigParser.poku.js +71 -0
- package/lib/helpers/depsUtils.js +5 -0
- package/lib/helpers/depsUtils.poku.js +55 -0
- package/lib/helpers/display.js +336 -23
- package/lib/helpers/display.poku.js +179 -43
- package/lib/helpers/evidenceUtils.js +58 -0
- package/lib/helpers/evidenceUtils.poku.js +54 -0
- package/lib/helpers/exportUtils.js +9 -0
- package/lib/helpers/gtfobins.js +142 -8
- package/lib/helpers/gtfobins.poku.js +24 -1
- package/lib/helpers/hbom.js +710 -0
- package/lib/helpers/hbom.poku.js +496 -0
- package/lib/helpers/hbomAnalysis.js +268 -0
- package/lib/helpers/hbomAnalysis.poku.js +249 -0
- package/lib/helpers/hbomLoader.js +35 -0
- package/lib/helpers/hostTopology.js +803 -0
- package/lib/helpers/hostTopology.poku.js +363 -0
- package/lib/helpers/inventoryStats.js +69 -0
- package/lib/helpers/inventoryStats.poku.js +86 -0
- package/lib/helpers/lolbas.js +19 -1
- package/lib/helpers/lolbas.poku.js +23 -0
- package/lib/helpers/mcpConfigParser.js +21 -5
- package/lib/helpers/mcpConfigParser.poku.js +39 -2
- package/lib/helpers/osqueryTransform.js +47 -0
- package/lib/helpers/osqueryTransform.poku.js +47 -0
- package/lib/helpers/plugins.js +349 -0
- package/lib/helpers/plugins.poku.js +57 -0
- package/lib/helpers/propertySanitizer.js +121 -0
- package/lib/helpers/protobom.js +156 -45
- package/lib/helpers/protobom.poku.js +140 -5
- package/lib/helpers/remote/dependency-track.js +36 -3
- package/lib/helpers/remote/dependency-track.poku.js +44 -0
- package/lib/helpers/source.js +24 -0
- package/lib/helpers/source.poku.js +32 -0
- package/lib/helpers/utils.js +2454 -198
- package/lib/helpers/utils.poku.js +1798 -74
- package/lib/managers/binary.e2e.poku.js +367 -0
- package/lib/managers/binary.js +2306 -350
- package/lib/managers/binary.poku.js +1700 -1
- package/lib/managers/docker.js +441 -95
- package/lib/managers/docker.poku.js +1479 -14
- package/lib/server/server.js +2 -24
- package/lib/server/server.poku.js +36 -1
- package/lib/stages/postgen/annotator.js +38 -0
- package/lib/stages/postgen/annotator.poku.js +107 -1
- package/lib/stages/postgen/auditBom.js +121 -18
- package/lib/stages/postgen/auditBom.poku.js +2967 -990
- package/lib/stages/postgen/hostTopologyAudit.poku.js +186 -0
- package/lib/stages/postgen/postgen.js +192 -1
- package/lib/stages/postgen/postgen.poku.js +321 -0
- package/lib/stages/postgen/ruleEngine.js +116 -0
- package/lib/stages/pregen/envAudit.js +14 -3
- package/package.json +24 -21
- package/types/bin/hbom.d.ts +3 -0
- package/types/bin/hbom.d.ts.map +1 -0
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts +44 -0
- package/types/lib/audit/index.d.ts.map +1 -1
- package/types/lib/audit/reporters.d.ts +16 -0
- package/types/lib/audit/reporters.d.ts.map +1 -1
- package/types/lib/audit/targets.d.ts.map +1 -1
- package/types/lib/cli/index.d.ts +16 -0
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/evinser/evinser.d.ts +4 -0
- package/types/lib/evinser/evinser.d.ts.map +1 -1
- package/types/lib/helpers/agentFormulationParser.d.ts.map +1 -1
- package/types/lib/helpers/analyzer.d.ts +33 -0
- package/types/lib/helpers/analyzer.d.ts.map +1 -1
- package/types/lib/helpers/analyzerScope.d.ts +11 -0
- package/types/lib/helpers/analyzerScope.d.ts.map +1 -0
- package/types/lib/helpers/asarutils.d.ts +34 -0
- package/types/lib/helpers/asarutils.d.ts.map +1 -0
- package/types/lib/helpers/auditCategories.d.ts +5 -0
- package/types/lib/helpers/auditCategories.d.ts.map +1 -1
- package/types/lib/helpers/cbomutils.d.ts +3 -2
- package/types/lib/helpers/cbomutils.d.ts.map +1 -1
- package/types/lib/helpers/chromextutils.d.ts.map +1 -1
- package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -1
- package/types/lib/helpers/communityAiConfigParser.d.ts.map +1 -1
- package/types/lib/helpers/depsUtils.d.ts.map +1 -1
- package/types/lib/helpers/display.d.ts +1 -0
- package/types/lib/helpers/display.d.ts.map +1 -1
- package/types/lib/helpers/evidenceUtils.d.ts +8 -0
- package/types/lib/helpers/evidenceUtils.d.ts.map +1 -0
- package/types/lib/helpers/exportUtils.d.ts.map +1 -1
- package/types/lib/helpers/gtfobins.d.ts +8 -0
- package/types/lib/helpers/gtfobins.d.ts.map +1 -1
- package/types/lib/helpers/hbom.d.ts +49 -0
- package/types/lib/helpers/hbom.d.ts.map +1 -0
- package/types/lib/helpers/hbomAnalysis.d.ts +62 -0
- package/types/lib/helpers/hbomAnalysis.d.ts.map +1 -0
- package/types/lib/helpers/hbomLoader.d.ts +7 -0
- package/types/lib/helpers/hbomLoader.d.ts.map +1 -0
- package/types/lib/helpers/hostTopology.d.ts +12 -0
- package/types/lib/helpers/hostTopology.d.ts.map +1 -0
- package/types/lib/helpers/inventoryStats.d.ts +11 -0
- package/types/lib/helpers/inventoryStats.d.ts.map +1 -0
- package/types/lib/helpers/lolbas.d.ts.map +1 -1
- package/types/lib/helpers/mcpConfigParser.d.ts +1 -1
- package/types/lib/helpers/mcpConfigParser.d.ts.map +1 -1
- package/types/lib/helpers/osqueryTransform.d.ts +3 -0
- package/types/lib/helpers/osqueryTransform.d.ts.map +1 -1
- package/types/lib/helpers/plugins.d.ts +58 -0
- package/types/lib/helpers/plugins.d.ts.map +1 -0
- package/types/lib/helpers/propertySanitizer.d.ts +3 -0
- package/types/lib/helpers/propertySanitizer.d.ts.map +1 -0
- package/types/lib/helpers/protobom.d.ts +3 -4
- package/types/lib/helpers/protobom.d.ts.map +1 -1
- package/types/lib/helpers/remote/dependency-track.d.ts +10 -3
- package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -1
- package/types/lib/helpers/source.d.ts.map +1 -1
- package/types/lib/helpers/utils.d.ts +74 -8
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts +5 -0
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts +3 -0
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/server/server.d.ts +2 -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/auditBom.d.ts +26 -1
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
- package/types/lib/stages/postgen/postgen.d.ts +2 -1
- 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/data/spdx-model-v3.0.1.jsonld +0 -15999
package/lib/cli/index.js
CHANGED
|
@@ -11,7 +11,6 @@ import { platform as _platform, arch, homedir } from "node:os";
|
|
|
11
11
|
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
12
12
|
import process from "node:process";
|
|
13
13
|
|
|
14
|
-
import got from "got";
|
|
15
14
|
import { PackageURL } from "packageurl-js";
|
|
16
15
|
import { gte, lte } from "semver";
|
|
17
16
|
import { parse } from "ssri";
|
|
@@ -35,8 +34,15 @@ import {
|
|
|
35
34
|
detectPythonMcpInventory,
|
|
36
35
|
findJSImportsExports,
|
|
37
36
|
} from "../helpers/analyzer.js";
|
|
37
|
+
import {
|
|
38
|
+
cleanupAsarTempDir,
|
|
39
|
+
extractAsarToTempDir,
|
|
40
|
+
parseAsarArchive,
|
|
41
|
+
rewriteExtractedArchivePaths,
|
|
42
|
+
} from "../helpers/asarutils.js";
|
|
38
43
|
import { expandBomAuditCategories } from "../helpers/auditCategories.js";
|
|
39
44
|
import { parseCaxaMetadata } from "../helpers/caxa.js";
|
|
45
|
+
import { collectSourceCryptoComponents } from "../helpers/cbomutils.js";
|
|
40
46
|
import {
|
|
41
47
|
CHROME_EXTENSION_PURL_TYPE,
|
|
42
48
|
collectChromeExtensionsFromPath,
|
|
@@ -49,27 +55,33 @@ import {
|
|
|
49
55
|
trimComponents,
|
|
50
56
|
} from "../helpers/depsUtils.js";
|
|
51
57
|
import { GIT_COMMAND } from "../helpers/envcontext.js";
|
|
52
|
-
import { thoughtLog } from "../helpers/logger.js";
|
|
53
58
|
import {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
createHbomDocument,
|
|
60
|
+
ensureHbomRuntimeSupport,
|
|
61
|
+
ensureNoMixedHbomProjectTypes,
|
|
62
|
+
hasHbomProjectType,
|
|
63
|
+
} from "../helpers/hbom.js";
|
|
64
|
+
import { mergeHostInventoryBoms } from "../helpers/hostTopology.js";
|
|
65
|
+
import { thoughtLog } from "../helpers/logger.js";
|
|
66
|
+
import { enrichComponentWithMcpMetadata } from "../helpers/mcp.js";
|
|
57
67
|
import { isPyLockFile } from "../helpers/pylockutils.js";
|
|
58
68
|
import {
|
|
59
69
|
buildDependencyTrackBomPayload,
|
|
60
|
-
|
|
70
|
+
getDependencyTrackBomApiUrl,
|
|
61
71
|
} from "../helpers/remote/dependency-track.js";
|
|
62
72
|
import { table } from "../helpers/table.js";
|
|
63
73
|
import {
|
|
64
74
|
addEvidenceForDotnet,
|
|
65
75
|
addEvidenceForImports,
|
|
66
76
|
addPlugin,
|
|
77
|
+
attachIdentityTools,
|
|
67
78
|
buildGradleCommandArguments,
|
|
68
79
|
buildObjectForCocoaPod,
|
|
69
80
|
buildObjectForGradleModule,
|
|
70
81
|
CARGO_CMD,
|
|
71
82
|
CDXGEN_VERSION,
|
|
72
83
|
CLJ_CMD,
|
|
84
|
+
cdxgenAgent,
|
|
73
85
|
checksumFile,
|
|
74
86
|
cleanupPlugin,
|
|
75
87
|
collectGemModuleNames,
|
|
@@ -88,6 +100,7 @@ import {
|
|
|
88
100
|
executeParallelGradleProperties,
|
|
89
101
|
executePodCommand,
|
|
90
102
|
extractJarArchive,
|
|
103
|
+
extractToolRefs,
|
|
91
104
|
frameworksList,
|
|
92
105
|
generatePixiLockFile,
|
|
93
106
|
getAllFiles,
|
|
@@ -109,6 +122,7 @@ import {
|
|
|
109
122
|
getTmpDir,
|
|
110
123
|
hasAnyProjectType,
|
|
111
124
|
includeMavenTestScope,
|
|
125
|
+
isAllowedHttpHost,
|
|
112
126
|
isDryRun,
|
|
113
127
|
isFeatureEnabled,
|
|
114
128
|
isMac,
|
|
@@ -134,6 +148,7 @@ import {
|
|
|
134
148
|
parseCloudBuildData,
|
|
135
149
|
parseCmakeLikeFile,
|
|
136
150
|
parseCocoaDependency,
|
|
151
|
+
parseColliderLockData,
|
|
137
152
|
parseComposerJson,
|
|
138
153
|
parseComposerLock,
|
|
139
154
|
parseConanData,
|
|
@@ -198,6 +213,7 @@ import {
|
|
|
198
213
|
readZipEntry,
|
|
199
214
|
recomputeScope,
|
|
200
215
|
recordActivity,
|
|
216
|
+
recordSensitiveFileRead,
|
|
201
217
|
resetActivityContext,
|
|
202
218
|
SWIFT_CMD,
|
|
203
219
|
safeExistsSync,
|
|
@@ -223,10 +239,12 @@ import {
|
|
|
223
239
|
VSCODE_EXTENSION_PURL_TYPE,
|
|
224
240
|
} from "../helpers/vsixutils.js";
|
|
225
241
|
import {
|
|
242
|
+
enrichOSComponentsWithTrustData,
|
|
226
243
|
executeOsQuery,
|
|
227
244
|
getBinaryBom,
|
|
228
245
|
getDotnetSlices,
|
|
229
246
|
getOSPackages,
|
|
247
|
+
getPluginToolComponents,
|
|
230
248
|
} from "../managers/binary.js";
|
|
231
249
|
import {
|
|
232
250
|
addSkippedSrcFiles,
|
|
@@ -329,7 +347,10 @@ const createDefaultParentComponent = (
|
|
|
329
347
|
group: options.projectGroup || "",
|
|
330
348
|
name: compName,
|
|
331
349
|
version: `${options.projectVersion}` || "latest",
|
|
332
|
-
type:
|
|
350
|
+
type:
|
|
351
|
+
type === "container" || compName.endsWith(".tar")
|
|
352
|
+
? "container"
|
|
353
|
+
: "application",
|
|
333
354
|
};
|
|
334
355
|
const ppurl = new PackageURL(
|
|
335
356
|
type,
|
|
@@ -344,6 +365,37 @@ const createDefaultParentComponent = (
|
|
|
344
365
|
return parentComponent;
|
|
345
366
|
};
|
|
346
367
|
|
|
368
|
+
const shouldIncludeNodeModulesDir = (options = {}, baseProjectTypes = []) => {
|
|
369
|
+
if (options.deep) {
|
|
370
|
+
return true;
|
|
371
|
+
}
|
|
372
|
+
const projectTypes = Array.isArray(options.projectType)
|
|
373
|
+
? options.projectType
|
|
374
|
+
: options.projectType
|
|
375
|
+
? [options.projectType]
|
|
376
|
+
: [];
|
|
377
|
+
if (!projectTypes.length) {
|
|
378
|
+
return true;
|
|
379
|
+
}
|
|
380
|
+
return baseProjectTypes.some((projectType) =>
|
|
381
|
+
projectTypes.every((selectedProjectType) =>
|
|
382
|
+
PROJECT_TYPE_ALIASES[projectType]?.includes(selectedProjectType),
|
|
383
|
+
),
|
|
384
|
+
);
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
const hasExplicitProjectTypeSelection = (options, baseProjectType) => {
|
|
388
|
+
options = options || {};
|
|
389
|
+
const projectTypes = Array.isArray(options.projectType)
|
|
390
|
+
? options.projectType
|
|
391
|
+
: options.projectType
|
|
392
|
+
? [options.projectType]
|
|
393
|
+
: [];
|
|
394
|
+
return projectTypes.some((selectedProjectType) =>
|
|
395
|
+
PROJECT_TYPE_ALIASES[baseProjectType]?.includes(selectedProjectType),
|
|
396
|
+
);
|
|
397
|
+
};
|
|
398
|
+
|
|
347
399
|
const determineParentComponent = (options) => {
|
|
348
400
|
let parentComponent;
|
|
349
401
|
if (options.parentComponent && Object.keys(options.parentComponent).length) {
|
|
@@ -815,6 +867,18 @@ function addMetadata(parentComponent = {}, options = {}, context = {}) {
|
|
|
815
867
|
value: options.allOSComponentTypes.sort().join("\\n"),
|
|
816
868
|
});
|
|
817
869
|
}
|
|
870
|
+
if (Number.isInteger(options?.unpackagedExecutableCount)) {
|
|
871
|
+
mproperties.push({
|
|
872
|
+
name: "cdx:container:unpackagedExecutableCount",
|
|
873
|
+
value: String(options.unpackagedExecutableCount),
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
if (Number.isInteger(options?.unpackagedSharedLibraryCount)) {
|
|
877
|
+
mproperties.push({
|
|
878
|
+
name: "cdx:container:unpackagedSharedLibraryCount",
|
|
879
|
+
value: String(options.unpackagedSharedLibraryCount),
|
|
880
|
+
});
|
|
881
|
+
}
|
|
818
882
|
// Should we move these to formulation?
|
|
819
883
|
if (options?.bundledSdks?.length) {
|
|
820
884
|
for (const sdk of options.bundledSdks) {
|
|
@@ -918,6 +982,9 @@ export function listComponents(options, allImports, pkg, ptype = "npm") {
|
|
|
918
982
|
return Object.keys(compMap).map((k) => compMap[k]);
|
|
919
983
|
}
|
|
920
984
|
|
|
985
|
+
// These component types do not have PURLs
|
|
986
|
+
const NON_PURL_TYPES = ["cryptographic-asset", "file", "data"];
|
|
987
|
+
|
|
921
988
|
/**
|
|
922
989
|
* Given the specified package, create a CycloneDX component and add it to the list.
|
|
923
990
|
*/
|
|
@@ -954,9 +1021,9 @@ function addComponent(
|
|
|
954
1021
|
}
|
|
955
1022
|
const version = pkg.version || "";
|
|
956
1023
|
const licenses = pkg.licenses || getLicenses(pkg);
|
|
957
|
-
let purl =
|
|
958
|
-
|
|
959
|
-
new PackageURL(
|
|
1024
|
+
let purl = pkg.purl;
|
|
1025
|
+
if (!purl && ptype) {
|
|
1026
|
+
purl = new PackageURL(
|
|
960
1027
|
ptype,
|
|
961
1028
|
encodeForPurl(group),
|
|
962
1029
|
encodeForPurl(name),
|
|
@@ -964,9 +1031,9 @@ function addComponent(
|
|
|
964
1031
|
pkg.qualifiers,
|
|
965
1032
|
encodeForPurl(pkg.subpath),
|
|
966
1033
|
);
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
if (ptype
|
|
1034
|
+
}
|
|
1035
|
+
let purlString = purl?.toString();
|
|
1036
|
+
if (NON_PURL_TYPES.includes(ptype) || NON_PURL_TYPES.includes(pkg.type)) {
|
|
970
1037
|
purl = undefined;
|
|
971
1038
|
purlString = undefined;
|
|
972
1039
|
}
|
|
@@ -1077,7 +1144,7 @@ function addComponent(
|
|
|
1077
1144
|
if (pkg.properties?.length) {
|
|
1078
1145
|
component.properties = pkg.properties;
|
|
1079
1146
|
}
|
|
1080
|
-
if (pkg.cryptoProperties
|
|
1147
|
+
if (pkg.cryptoProperties && typeof pkg.cryptoProperties === "object") {
|
|
1081
1148
|
component.cryptoProperties = pkg.cryptoProperties;
|
|
1082
1149
|
}
|
|
1083
1150
|
// Retain nested components
|
|
@@ -1368,17 +1435,21 @@ export async function createJarBom(path, options) {
|
|
|
1368
1435
|
let pkgList = [];
|
|
1369
1436
|
let jarFiles;
|
|
1370
1437
|
let nsMapping = {};
|
|
1371
|
-
|
|
1372
|
-
options
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
if (typeof
|
|
1376
|
-
|
|
1438
|
+
const searchOptions = {
|
|
1439
|
+
...options,
|
|
1440
|
+
exclude: [...(options.exclude || [])],
|
|
1441
|
+
};
|
|
1442
|
+
if (typeof searchOptions.includeNodeModulesDir === "undefined") {
|
|
1443
|
+
searchOptions.includeNodeModulesDir = shouldIncludeNodeModulesDir(options, [
|
|
1444
|
+
"jar",
|
|
1445
|
+
"war",
|
|
1446
|
+
"ear",
|
|
1447
|
+
]);
|
|
1377
1448
|
}
|
|
1378
1449
|
// Exclude certain directories during oci sbom generation
|
|
1379
1450
|
if (hasAnyProjectType(["oci"], options, false)) {
|
|
1380
|
-
|
|
1381
|
-
|
|
1451
|
+
searchOptions.exclude.push("**/android-sdk*/**");
|
|
1452
|
+
searchOptions.exclude.push("**/.sdkman/**");
|
|
1382
1453
|
}
|
|
1383
1454
|
const parentComponent = createDefaultParentComponent(path, "maven", options);
|
|
1384
1455
|
if (options.useGradleCache) {
|
|
@@ -1402,14 +1473,14 @@ export async function createJarBom(path, options) {
|
|
|
1402
1473
|
jarFiles = getAllFiles(
|
|
1403
1474
|
path,
|
|
1404
1475
|
`${options.multiProject ? "**/" : ""}*.[jw]ar`,
|
|
1405
|
-
|
|
1476
|
+
searchOptions,
|
|
1406
1477
|
);
|
|
1407
1478
|
}
|
|
1408
1479
|
// Jenkins plugins
|
|
1409
1480
|
const hpiFiles = getAllFiles(
|
|
1410
1481
|
path,
|
|
1411
1482
|
`${options.multiProject ? "**/" : ""}*.hpi`,
|
|
1412
|
-
|
|
1483
|
+
searchOptions,
|
|
1413
1484
|
);
|
|
1414
1485
|
if (hpiFiles.length) {
|
|
1415
1486
|
jarFiles = jarFiles.concat(hpiFiles);
|
|
@@ -1464,6 +1535,13 @@ export function createBinaryBom(path, options) {
|
|
|
1464
1535
|
const binaryBom = JSON.parse(
|
|
1465
1536
|
readFileSync(binaryBomFile, { encoding: "utf-8" }),
|
|
1466
1537
|
);
|
|
1538
|
+
attachIdentityTools(
|
|
1539
|
+
binaryBom?.components,
|
|
1540
|
+
extractToolRefs(
|
|
1541
|
+
binaryBom?.metadata?.tools,
|
|
1542
|
+
(tool) => tool?.name !== "cdxgen",
|
|
1543
|
+
),
|
|
1544
|
+
);
|
|
1467
1545
|
return {
|
|
1468
1546
|
bomJson: binaryBom,
|
|
1469
1547
|
dependencies: binaryBom.dependencies,
|
|
@@ -1891,6 +1969,10 @@ export async function createJavaBom(path, options) {
|
|
|
1891
1969
|
) {
|
|
1892
1970
|
tools = bomJsonObj.metadata.tools;
|
|
1893
1971
|
}
|
|
1972
|
+
const toolRefs = extractToolRefs(
|
|
1973
|
+
bomJsonObj?.metadata?.tools,
|
|
1974
|
+
(tool) => tool?.name !== "cdxgen",
|
|
1975
|
+
);
|
|
1894
1976
|
if (
|
|
1895
1977
|
bomJsonObj.metadata?.component &&
|
|
1896
1978
|
!Object.keys(parentComponent).length
|
|
@@ -1927,6 +2009,7 @@ export async function createJavaBom(path, options) {
|
|
|
1927
2009
|
name: "SrcFile",
|
|
1928
2010
|
value: srcPomFile,
|
|
1929
2011
|
});
|
|
2012
|
+
attachIdentityTools(acomp, toolRefs);
|
|
1930
2013
|
}
|
|
1931
2014
|
}
|
|
1932
2015
|
pkgList = pkgList.concat(bomJsonObj.components);
|
|
@@ -2728,11 +2811,10 @@ export async function createJavaBom(path, options) {
|
|
|
2728
2811
|
}
|
|
2729
2812
|
|
|
2730
2813
|
/**
|
|
2731
|
-
*
|
|
2814
|
+
* Identify the requested AI inventory project types.
|
|
2732
2815
|
*
|
|
2733
|
-
* @param {string} path to the project
|
|
2734
2816
|
* @param {Object} options Parse options from the cli
|
|
2735
|
-
* @returns {
|
|
2817
|
+
* @returns {string[]} Requested AI inventory types
|
|
2736
2818
|
*/
|
|
2737
2819
|
function getRequestedAiInventoryTypes(options) {
|
|
2738
2820
|
return AI_INVENTORY_PROJECT_TYPES.filter((type) =>
|
|
@@ -2746,6 +2828,48 @@ function getExcludedAiInventoryTypes(options) {
|
|
|
2746
2828
|
);
|
|
2747
2829
|
}
|
|
2748
2830
|
|
|
2831
|
+
function filterIncludedAiInventoryTypes(
|
|
2832
|
+
includedAiInventoryTypes,
|
|
2833
|
+
excludedAiInventoryTypes,
|
|
2834
|
+
) {
|
|
2835
|
+
return [...new Set(includedAiInventoryTypes)].filter(
|
|
2836
|
+
(type) => !excludedAiInventoryTypes.includes(type),
|
|
2837
|
+
);
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2840
|
+
/**
|
|
2841
|
+
* Determine which AI inventory types should be collected for a scan.
|
|
2842
|
+
*
|
|
2843
|
+
* This combines explicit project-type opt-ins with BOM audit category-driven
|
|
2844
|
+
* opt-ins, then removes any explicitly excluded inventory types.
|
|
2845
|
+
*
|
|
2846
|
+
* @param {Object} options Parse options from the CLI
|
|
2847
|
+
* @returns {string[]} AI inventory types to collect
|
|
2848
|
+
*/
|
|
2849
|
+
function getIncludedAiInventoryTypes(options) {
|
|
2850
|
+
const requestedAiInventoryTypes = getRequestedAiInventoryTypes(options);
|
|
2851
|
+
const excludedAiInventoryTypes = getExcludedAiInventoryTypes(options);
|
|
2852
|
+
const exactAiInventoryType = getExactAiInventoryType(options);
|
|
2853
|
+
if (exactAiInventoryType) {
|
|
2854
|
+
return filterIncludedAiInventoryTypes(
|
|
2855
|
+
requestedAiInventoryTypes,
|
|
2856
|
+
excludedAiInventoryTypes,
|
|
2857
|
+
);
|
|
2858
|
+
}
|
|
2859
|
+
const auditCategories = expandBomAuditCategories(options?.bomAuditCategories);
|
|
2860
|
+
const includedAiInventoryTypes = [...requestedAiInventoryTypes];
|
|
2861
|
+
if (auditCategories.includes("ai-agent")) {
|
|
2862
|
+
includedAiInventoryTypes.push("ai-skill");
|
|
2863
|
+
}
|
|
2864
|
+
if (auditCategories.includes("mcp-server")) {
|
|
2865
|
+
includedAiInventoryTypes.push("mcp");
|
|
2866
|
+
}
|
|
2867
|
+
return filterIncludedAiInventoryTypes(
|
|
2868
|
+
includedAiInventoryTypes,
|
|
2869
|
+
excludedAiInventoryTypes,
|
|
2870
|
+
);
|
|
2871
|
+
}
|
|
2872
|
+
|
|
2749
2873
|
function getExactAiInventoryType(options) {
|
|
2750
2874
|
const requestedAiInventoryTypes = getRequestedAiInventoryTypes(options);
|
|
2751
2875
|
return requestedAiInventoryTypes.length === 1 &&
|
|
@@ -2755,22 +2879,14 @@ function getExactAiInventoryType(options) {
|
|
|
2755
2879
|
: undefined;
|
|
2756
2880
|
}
|
|
2757
2881
|
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
)
|
|
2767
|
-
) {
|
|
2768
|
-
return true;
|
|
2769
|
-
}
|
|
2770
|
-
return Object.keys(allImports).some((importName) => {
|
|
2771
|
-
const classification = classifyMcpReference(importName);
|
|
2772
|
-
return classification.isMcp;
|
|
2773
|
-
});
|
|
2882
|
+
/**
|
|
2883
|
+
* Determine whether MCP source-code analysis should run for the current scan.
|
|
2884
|
+
*
|
|
2885
|
+
* @param {string[]} includedAiInventoryTypes AI inventory types selected for collection
|
|
2886
|
+
* @returns {boolean} True when MCP inventory collection is enabled
|
|
2887
|
+
*/
|
|
2888
|
+
function shouldDetectMcpInventory(includedAiInventoryTypes) {
|
|
2889
|
+
return includedAiInventoryTypes.includes("mcp");
|
|
2774
2890
|
}
|
|
2775
2891
|
|
|
2776
2892
|
function summarizeAiInventoryNames(subjects, discoveryPath, kindSet) {
|
|
@@ -2865,14 +2981,8 @@ export async function createNodejsBom(path, options) {
|
|
|
2865
2981
|
let parentComponent = {};
|
|
2866
2982
|
const parentSubComponents = [];
|
|
2867
2983
|
let ppurl = "";
|
|
2868
|
-
const requestedAiInventoryTypes = getRequestedAiInventoryTypes(options);
|
|
2869
|
-
const excludedAiInventoryTypes = getExcludedAiInventoryTypes(options);
|
|
2870
2984
|
const exactAiInventoryType = getExactAiInventoryType(options);
|
|
2871
|
-
const includedAiInventoryTypes =
|
|
2872
|
-
? requestedAiInventoryTypes
|
|
2873
|
-
: AI_INVENTORY_PROJECT_TYPES.filter(
|
|
2874
|
-
(type) => !excludedAiInventoryTypes.includes(type),
|
|
2875
|
-
);
|
|
2985
|
+
const includedAiInventoryTypes = getIncludedAiInventoryTypes(options);
|
|
2876
2986
|
let aiInventory = { components: [], dependencies: [], services: [] };
|
|
2877
2987
|
// Docker mode requires special handling
|
|
2878
2988
|
if (hasAnyProjectType(["docker", "oci", "container", "os"], options, false)) {
|
|
@@ -2924,16 +3034,13 @@ export async function createNodejsBom(path, options) {
|
|
|
2924
3034
|
const retData = await findJSImportsExports(path, options.deep);
|
|
2925
3035
|
allImports = retData.allImports;
|
|
2926
3036
|
allExports = retData.allExports;
|
|
2927
|
-
if (shouldDetectMcpInventory(
|
|
3037
|
+
if (shouldDetectMcpInventory(includedAiInventoryTypes)) {
|
|
2928
3038
|
mcpInventory = detectMcpInventory(path, options.deep);
|
|
2929
3039
|
}
|
|
2930
3040
|
}
|
|
2931
3041
|
if (includedAiInventoryTypes.length) {
|
|
2932
3042
|
aiInventory = collectAiInventory(path, options, includedAiInventoryTypes);
|
|
2933
3043
|
}
|
|
2934
|
-
if (excludedAiInventoryTypes.includes("mcp")) {
|
|
2935
|
-
mcpInventory = { components: [], dependencies: [], services: [] };
|
|
2936
|
-
}
|
|
2937
3044
|
const aiInventorySummary = summarizeAiInventory(aiInventory);
|
|
2938
3045
|
if (!exactAiInventoryType) {
|
|
2939
3046
|
if (aiInventorySummary.instructionCount || aiInventorySummary.skillCount) {
|
|
@@ -2946,7 +3053,6 @@ export async function createNodejsBom(path, options) {
|
|
|
2946
3053
|
`I found ${aiInventorySummary.mcpConfigCount} MCP config component(s). Use '--exclude-type mcp' to drop them, or '--bom-audit --bom-audit-categories ai-inventory --tlp-classification AMBER' to keep and flag them.`,
|
|
2947
3054
|
);
|
|
2948
3055
|
}
|
|
2949
|
-
emitAiInventorySummary(aiInventory, path);
|
|
2950
3056
|
}
|
|
2951
3057
|
if (exactAiInventoryType === "ai-skill") {
|
|
2952
3058
|
const exactComponents = trimComponents([...(aiInventory.components || [])]);
|
|
@@ -3126,11 +3232,15 @@ export async function createNodejsBom(path, options) {
|
|
|
3126
3232
|
}
|
|
3127
3233
|
const basePath = dirname(apkgJson);
|
|
3128
3234
|
let npmrcData;
|
|
3129
|
-
|
|
3235
|
+
const npmrcFile = join(basePath, ".npmrc");
|
|
3236
|
+
if (safeExistsSync(npmrcFile)) {
|
|
3130
3237
|
thoughtLog(
|
|
3131
3238
|
"Wait, there is a .npmrc file here! I'm going to check if it has anything malicious.",
|
|
3132
3239
|
);
|
|
3133
|
-
npmrcData = readFileSync(
|
|
3240
|
+
npmrcData = readFileSync(npmrcFile, "utf-8");
|
|
3241
|
+
recordSensitiveFileRead(npmrcFile, {
|
|
3242
|
+
label: "npm registry configuration",
|
|
3243
|
+
});
|
|
3134
3244
|
const npmrcObj = parseNpmrc(npmrcData);
|
|
3135
3245
|
for (const [key, value] of Object.entries(npmrcObj)) {
|
|
3136
3246
|
const baseKey = key.replace(/^(?:\/\/[^/]+\/|@[^:]+:)/, "");
|
|
@@ -4061,14 +4171,7 @@ export async function createPythonBom(path, options) {
|
|
|
4061
4171
|
let dependencies = [];
|
|
4062
4172
|
let pkgList = [];
|
|
4063
4173
|
let formulationList = [];
|
|
4064
|
-
const
|
|
4065
|
-
const excludedAiInventoryTypes = getExcludedAiInventoryTypes(options);
|
|
4066
|
-
const includedAiInventoryTypes = AI_INVENTORY_PROJECT_TYPES.filter(
|
|
4067
|
-
(type) =>
|
|
4068
|
-
(!requestedAiInventoryTypes.length ||
|
|
4069
|
-
requestedAiInventoryTypes.includes(type)) &&
|
|
4070
|
-
!excludedAiInventoryTypes.includes(type),
|
|
4071
|
-
);
|
|
4174
|
+
const includedAiInventoryTypes = getIncludedAiInventoryTypes(options);
|
|
4072
4175
|
let aiInventory = { components: [], dependencies: [], services: [] };
|
|
4073
4176
|
let mcpInventory = { components: [], dependencies: [], services: [] };
|
|
4074
4177
|
const tempDir = safeMkdtempSync(join(getTmpDir(), "cdxgen-venv-"));
|
|
@@ -5416,6 +5519,11 @@ export function createCppBom(path, options) {
|
|
|
5416
5519
|
let parentComponent;
|
|
5417
5520
|
let dependencies = [];
|
|
5418
5521
|
const addedParentComponentsMap = {};
|
|
5522
|
+
const colliderLockFiles = getAllFiles(
|
|
5523
|
+
path,
|
|
5524
|
+
`${options.multiProject ? "**/" : ""}collider.lock`,
|
|
5525
|
+
options,
|
|
5526
|
+
);
|
|
5419
5527
|
const conanLockFiles = getAllFiles(
|
|
5420
5528
|
path,
|
|
5421
5529
|
`${options.multiProject ? "**/" : ""}conan.lock`,
|
|
@@ -5492,6 +5600,39 @@ export function createCppBom(path, options) {
|
|
|
5492
5600
|
}
|
|
5493
5601
|
}
|
|
5494
5602
|
}
|
|
5603
|
+
if (colliderLockFiles.length) {
|
|
5604
|
+
for (const f of colliderLockFiles) {
|
|
5605
|
+
if (DEBUG_MODE) {
|
|
5606
|
+
console.log(`Parsing ${f}`);
|
|
5607
|
+
}
|
|
5608
|
+
const colliderLockData = readFileSync(f, { encoding: "utf-8" });
|
|
5609
|
+
const {
|
|
5610
|
+
pkgList: colliderPkgList,
|
|
5611
|
+
dependencies: colliderDependencies,
|
|
5612
|
+
parentComponentDependencies: parentCompDeps,
|
|
5613
|
+
} = parseColliderLockData(colliderLockData, f);
|
|
5614
|
+
|
|
5615
|
+
if (colliderPkgList.length) {
|
|
5616
|
+
pkgList = pkgList.concat(colliderPkgList);
|
|
5617
|
+
}
|
|
5618
|
+
|
|
5619
|
+
if (Object.keys(colliderDependencies).length) {
|
|
5620
|
+
dependencies = mergeDependencies(
|
|
5621
|
+
dependencies,
|
|
5622
|
+
Object.keys(colliderDependencies).map((dependentBomRef) => ({
|
|
5623
|
+
ref: dependentBomRef,
|
|
5624
|
+
dependsOn: colliderDependencies[dependentBomRef],
|
|
5625
|
+
})),
|
|
5626
|
+
);
|
|
5627
|
+
}
|
|
5628
|
+
|
|
5629
|
+
if (parentCompDeps.length) {
|
|
5630
|
+
parentComponentDependencies = [
|
|
5631
|
+
...new Set(parentComponentDependencies.concat(parentCompDeps)),
|
|
5632
|
+
];
|
|
5633
|
+
}
|
|
5634
|
+
}
|
|
5635
|
+
}
|
|
5495
5636
|
if (cmakeLikeFiles.length) {
|
|
5496
5637
|
for (const f of cmakeLikeFiles) {
|
|
5497
5638
|
if (DEBUG_MODE) {
|
|
@@ -5876,6 +6017,7 @@ export function createOSBom(_path, options) {
|
|
|
5876
6017
|
let pkgList = [];
|
|
5877
6018
|
let bomData = {};
|
|
5878
6019
|
let parentComponent = {};
|
|
6020
|
+
let externalTools = getPluginToolComponents(["osquery"]);
|
|
5879
6021
|
for (const queryCategory of Object.keys(osQueries)) {
|
|
5880
6022
|
const queryObj = osQueries[queryCategory];
|
|
5881
6023
|
const results = executeOsQuery(queryObj.query);
|
|
@@ -5894,6 +6036,20 @@ export function createOSBom(_path, options) {
|
|
|
5894
6036
|
);
|
|
5895
6037
|
}
|
|
5896
6038
|
} // for
|
|
6039
|
+
const hostTrustInventory = enrichOSComponentsWithTrustData(pkgList);
|
|
6040
|
+
if (hostTrustInventory?.components?.length) {
|
|
6041
|
+
pkgList = hostTrustInventory.components;
|
|
6042
|
+
}
|
|
6043
|
+
if (hostTrustInventory?.tools?.length) {
|
|
6044
|
+
externalTools = externalTools.concat(hostTrustInventory.tools);
|
|
6045
|
+
}
|
|
6046
|
+
if (externalTools.length) {
|
|
6047
|
+
options.tools = Array.from(
|
|
6048
|
+
new Map(
|
|
6049
|
+
externalTools.map((tool) => [tool["bom-ref"] || tool.name, tool]),
|
|
6050
|
+
).values(),
|
|
6051
|
+
);
|
|
6052
|
+
}
|
|
5897
6053
|
if (pkgList.length) {
|
|
5898
6054
|
bomData = buildBomNSData(options, pkgList, "", {
|
|
5899
6055
|
src: "",
|
|
@@ -6830,24 +6986,26 @@ export async function createContainerSpecLikeBom(path, options) {
|
|
|
6830
6986
|
export function createPHPBom(path, options) {
|
|
6831
6987
|
let dependencies = [];
|
|
6832
6988
|
let parentComponent = {};
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6989
|
+
const searchOptions = {
|
|
6990
|
+
...options,
|
|
6991
|
+
includeNodeModulesDir:
|
|
6992
|
+
typeof options.includeNodeModulesDir === "undefined"
|
|
6993
|
+
? shouldIncludeNodeModulesDir(options, ["php"])
|
|
6994
|
+
: options.includeNodeModulesDir,
|
|
6995
|
+
};
|
|
6996
|
+
const composerLockSearchOptions = {
|
|
6997
|
+
...searchOptions,
|
|
6998
|
+
exclude: [...(options.exclude || []), "**/vendor/**"],
|
|
6999
|
+
};
|
|
6837
7000
|
const composerJsonFiles = getAllFiles(
|
|
6838
7001
|
path,
|
|
6839
7002
|
`${options.multiProject ? "**/" : ""}composer.json`,
|
|
6840
|
-
|
|
7003
|
+
searchOptions,
|
|
6841
7004
|
);
|
|
6842
|
-
if (!options.exclude) {
|
|
6843
|
-
options.exclude = [];
|
|
6844
|
-
}
|
|
6845
|
-
// Ignore vendor directories for lock files
|
|
6846
|
-
options.exclude.push("**/vendor/**");
|
|
6847
7005
|
let composerLockFiles = getAllFiles(
|
|
6848
7006
|
path,
|
|
6849
7007
|
`${options.multiProject ? "**/" : ""}composer.lock`,
|
|
6850
|
-
|
|
7008
|
+
composerLockSearchOptions,
|
|
6851
7009
|
);
|
|
6852
7010
|
let pkgList = [];
|
|
6853
7011
|
const composerJsonMode = composerJsonFiles.length;
|
|
@@ -6910,7 +7068,7 @@ export function createPHPBom(path, options) {
|
|
|
6910
7068
|
composerLockFiles = getAllFiles(
|
|
6911
7069
|
path,
|
|
6912
7070
|
`${options.multiProject ? "**/" : ""}composer.lock`,
|
|
6913
|
-
|
|
7071
|
+
composerLockSearchOptions,
|
|
6914
7072
|
);
|
|
6915
7073
|
if (composerLockFiles.length) {
|
|
6916
7074
|
// Look for any root composer.json to capture the parentComponent
|
|
@@ -7695,6 +7853,10 @@ export async function createVscodeExtensionBom(path, options) {
|
|
|
7695
7853
|
let pkgList = [];
|
|
7696
7854
|
let dependencies = [];
|
|
7697
7855
|
const tempDirs = [];
|
|
7856
|
+
const shouldDiscoverInstalledIdeExtensions = hasExplicitProjectTypeSelection(
|
|
7857
|
+
options,
|
|
7858
|
+
"vscode-extension",
|
|
7859
|
+
);
|
|
7698
7860
|
|
|
7699
7861
|
// Mode 1: Scan for .vsix files in the given directory, or treat the input
|
|
7700
7862
|
// path as a single .vsix file.
|
|
@@ -7740,7 +7902,7 @@ export async function createVscodeExtensionBom(path, options) {
|
|
|
7740
7902
|
}
|
|
7741
7903
|
|
|
7742
7904
|
// Mode 2: Auto-discover extensions from known IDE locations
|
|
7743
|
-
if (
|
|
7905
|
+
if (shouldDiscoverInstalledIdeExtensions) {
|
|
7744
7906
|
const ideDirs = discoverIdeExtensionDirs();
|
|
7745
7907
|
if (ideDirs.length) {
|
|
7746
7908
|
if (DEBUG_MODE) {
|
|
@@ -7782,6 +7944,198 @@ export async function createVscodeExtensionBom(path, options) {
|
|
|
7782
7944
|
});
|
|
7783
7945
|
}
|
|
7784
7946
|
|
|
7947
|
+
/**
|
|
7948
|
+
* Function to create BOM for Electron ASAR archives.
|
|
7949
|
+
*
|
|
7950
|
+
* @param {string} path to a single archive or a directory to scan
|
|
7951
|
+
* @param {Object} options Parse options from the cli
|
|
7952
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
7953
|
+
*/
|
|
7954
|
+
export async function createAsarBom(path, options) {
|
|
7955
|
+
let pkgList = [];
|
|
7956
|
+
let dependencies = [];
|
|
7957
|
+
let parentComponent = {};
|
|
7958
|
+
const tempDirs = [];
|
|
7959
|
+
const processedArchives = new Set();
|
|
7960
|
+
const maxNestedAsarDepth = 4;
|
|
7961
|
+
const explicitAsarPath = path.endsWith(".asar") ? resolve(path) : undefined;
|
|
7962
|
+
const asarFiles = explicitAsarPath
|
|
7963
|
+
? [explicitAsarPath]
|
|
7964
|
+
: getAllFiles(path, `${options.multiProject ? "**/" : ""}*.asar`, options);
|
|
7965
|
+
|
|
7966
|
+
const aggregateArchiveResults = (
|
|
7967
|
+
archiveAnalysis,
|
|
7968
|
+
isPrimaryArchive = false,
|
|
7969
|
+
) => {
|
|
7970
|
+
if (
|
|
7971
|
+
archiveAnalysis.parentComponent &&
|
|
7972
|
+
Object.keys(archiveAnalysis.parentComponent).length
|
|
7973
|
+
) {
|
|
7974
|
+
if (isPrimaryArchive && !Object.keys(parentComponent).length) {
|
|
7975
|
+
parentComponent = archiveAnalysis.parentComponent;
|
|
7976
|
+
} else {
|
|
7977
|
+
pkgList.push(archiveAnalysis.parentComponent);
|
|
7978
|
+
}
|
|
7979
|
+
}
|
|
7980
|
+
if (archiveAnalysis.components?.length) {
|
|
7981
|
+
pkgList = pkgList.concat(archiveAnalysis.components);
|
|
7982
|
+
}
|
|
7983
|
+
if (archiveAnalysis.dependencies?.length) {
|
|
7984
|
+
dependencies = mergeDependencies(
|
|
7985
|
+
dependencies,
|
|
7986
|
+
archiveAnalysis.dependencies,
|
|
7987
|
+
parentComponent,
|
|
7988
|
+
);
|
|
7989
|
+
}
|
|
7990
|
+
};
|
|
7991
|
+
|
|
7992
|
+
const analyzeExtractedArchive = async (
|
|
7993
|
+
extractedDir,
|
|
7994
|
+
archiveAnalysis,
|
|
7995
|
+
archiveIdentityPath,
|
|
7996
|
+
) => {
|
|
7997
|
+
if (!archiveAnalysis.packageManifestPaths?.length) {
|
|
7998
|
+
return undefined;
|
|
7999
|
+
}
|
|
8000
|
+
const nodeBomOptions = {
|
|
8001
|
+
...options,
|
|
8002
|
+
installDeps: false,
|
|
8003
|
+
multiProject: true,
|
|
8004
|
+
noBabel: false,
|
|
8005
|
+
path: extractedDir,
|
|
8006
|
+
projectType: ["js"],
|
|
8007
|
+
};
|
|
8008
|
+
const nodeBomData = await createNodejsBom(extractedDir, nodeBomOptions);
|
|
8009
|
+
if (nodeBomData?.bomJson?.components?.length) {
|
|
8010
|
+
rewriteExtractedArchivePaths(
|
|
8011
|
+
nodeBomData.bomJson.components,
|
|
8012
|
+
extractedDir,
|
|
8013
|
+
archiveIdentityPath,
|
|
8014
|
+
);
|
|
8015
|
+
pkgList = pkgList.concat(nodeBomData.bomJson.components);
|
|
8016
|
+
}
|
|
8017
|
+
if (nodeBomData?.bomJson?.dependencies?.length) {
|
|
8018
|
+
dependencies = mergeDependencies(
|
|
8019
|
+
dependencies,
|
|
8020
|
+
nodeBomData.bomJson.dependencies,
|
|
8021
|
+
);
|
|
8022
|
+
}
|
|
8023
|
+
if (
|
|
8024
|
+
archiveAnalysis.parentComponent?.["bom-ref"] &&
|
|
8025
|
+
nodeBomData?.parentComponent?.["bom-ref"] &&
|
|
8026
|
+
archiveAnalysis.parentComponent["bom-ref"] !==
|
|
8027
|
+
nodeBomData.parentComponent["bom-ref"]
|
|
8028
|
+
) {
|
|
8029
|
+
rewriteExtractedArchivePaths(
|
|
8030
|
+
nodeBomData.parentComponent,
|
|
8031
|
+
extractedDir,
|
|
8032
|
+
archiveIdentityPath,
|
|
8033
|
+
);
|
|
8034
|
+
dependencies = mergeDependencies(dependencies, [
|
|
8035
|
+
{
|
|
8036
|
+
ref: archiveAnalysis.parentComponent["bom-ref"],
|
|
8037
|
+
dependsOn: [nodeBomData.parentComponent["bom-ref"]],
|
|
8038
|
+
},
|
|
8039
|
+
]);
|
|
8040
|
+
}
|
|
8041
|
+
return nodeBomData;
|
|
8042
|
+
};
|
|
8043
|
+
|
|
8044
|
+
const processAsarArchive = async (
|
|
8045
|
+
archivePath,
|
|
8046
|
+
archiveIdentityPath,
|
|
8047
|
+
isPrimaryArchive = false,
|
|
8048
|
+
depth = 0,
|
|
8049
|
+
) => {
|
|
8050
|
+
const processedKey = archiveIdentityPath;
|
|
8051
|
+
if (processedArchives.has(processedKey)) {
|
|
8052
|
+
return undefined;
|
|
8053
|
+
}
|
|
8054
|
+
processedArchives.add(processedKey);
|
|
8055
|
+
const archiveAnalysis = await parseAsarArchive(archivePath, {
|
|
8056
|
+
...options,
|
|
8057
|
+
asarVirtualPath: archiveIdentityPath,
|
|
8058
|
+
});
|
|
8059
|
+
aggregateArchiveResults(archiveAnalysis, isPrimaryArchive);
|
|
8060
|
+
const shouldExtract =
|
|
8061
|
+
archiveAnalysis.packageManifestPaths?.length ||
|
|
8062
|
+
(depth < maxNestedAsarDepth &&
|
|
8063
|
+
archiveAnalysis.summary?.nestedArchiveCount > 0);
|
|
8064
|
+
if (!shouldExtract) {
|
|
8065
|
+
return archiveAnalysis.parentComponent?.["bom-ref"];
|
|
8066
|
+
}
|
|
8067
|
+
const extractedDir = await extractAsarToTempDir(archivePath);
|
|
8068
|
+
if (!extractedDir) {
|
|
8069
|
+
return archiveAnalysis.parentComponent?.["bom-ref"];
|
|
8070
|
+
}
|
|
8071
|
+
tempDirs.push(extractedDir);
|
|
8072
|
+
await analyzeExtractedArchive(
|
|
8073
|
+
extractedDir,
|
|
8074
|
+
archiveAnalysis,
|
|
8075
|
+
archiveIdentityPath,
|
|
8076
|
+
);
|
|
8077
|
+
if (depth < maxNestedAsarDepth) {
|
|
8078
|
+
const nestedAsarFiles = getAllFiles(extractedDir, "**/*.asar", options);
|
|
8079
|
+
for (const nestedArchivePath of nestedAsarFiles) {
|
|
8080
|
+
const relativeNestedArchivePath = relative(
|
|
8081
|
+
extractedDir,
|
|
8082
|
+
nestedArchivePath,
|
|
8083
|
+
).replaceAll("\\", "/");
|
|
8084
|
+
if (
|
|
8085
|
+
!relativeNestedArchivePath ||
|
|
8086
|
+
relativeNestedArchivePath.startsWith("..")
|
|
8087
|
+
) {
|
|
8088
|
+
continue;
|
|
8089
|
+
}
|
|
8090
|
+
const nestedArchiveIdentityPath = `${archiveIdentityPath}#/${relativeNestedArchivePath}`;
|
|
8091
|
+
const nestedParentRef = await processAsarArchive(
|
|
8092
|
+
nestedArchivePath,
|
|
8093
|
+
nestedArchiveIdentityPath,
|
|
8094
|
+
false,
|
|
8095
|
+
depth + 1,
|
|
8096
|
+
);
|
|
8097
|
+
if (
|
|
8098
|
+
archiveAnalysis.parentComponent?.["bom-ref"] &&
|
|
8099
|
+
nestedParentRef &&
|
|
8100
|
+
archiveAnalysis.parentComponent["bom-ref"] !== nestedParentRef
|
|
8101
|
+
) {
|
|
8102
|
+
dependencies = mergeDependencies(dependencies, [
|
|
8103
|
+
{
|
|
8104
|
+
ref: archiveAnalysis.parentComponent["bom-ref"],
|
|
8105
|
+
dependsOn: [nestedParentRef],
|
|
8106
|
+
},
|
|
8107
|
+
]);
|
|
8108
|
+
}
|
|
8109
|
+
}
|
|
8110
|
+
}
|
|
8111
|
+
return archiveAnalysis.parentComponent?.["bom-ref"];
|
|
8112
|
+
};
|
|
8113
|
+
try {
|
|
8114
|
+
for (const archivePath of asarFiles) {
|
|
8115
|
+
const isPrimaryArchive =
|
|
8116
|
+
explicitAsarPath && resolve(archivePath) === explicitAsarPath;
|
|
8117
|
+
await processAsarArchive(
|
|
8118
|
+
archivePath,
|
|
8119
|
+
resolve(archivePath),
|
|
8120
|
+
isPrimaryArchive,
|
|
8121
|
+
0,
|
|
8122
|
+
);
|
|
8123
|
+
}
|
|
8124
|
+
} finally {
|
|
8125
|
+
for (const tempDir of tempDirs) {
|
|
8126
|
+
cleanupAsarTempDir(tempDir);
|
|
8127
|
+
}
|
|
8128
|
+
}
|
|
8129
|
+
pkgList = trimComponents(pkgList);
|
|
8130
|
+
return buildBomNSData(options, pkgList, "asar", {
|
|
8131
|
+
src: path,
|
|
8132
|
+
filename: asarFiles.join(", "),
|
|
8133
|
+
nsMapping: {},
|
|
8134
|
+
dependencies,
|
|
8135
|
+
parentComponent,
|
|
8136
|
+
});
|
|
8137
|
+
}
|
|
8138
|
+
|
|
7785
8139
|
/**
|
|
7786
8140
|
* Function to create BOM for installed Chrome and Chromium-based browser extensions.
|
|
7787
8141
|
*
|
|
@@ -7793,7 +8147,8 @@ export async function createChromeExtensionBom(path, options) {
|
|
|
7793
8147
|
let dependencies = [];
|
|
7794
8148
|
let sourcePaths = [];
|
|
7795
8149
|
const directResult = collectChromeExtensionsFromPath(path);
|
|
7796
|
-
const
|
|
8150
|
+
const shouldDiscoverInstalledChromeExtensions =
|
|
8151
|
+
hasExplicitProjectTypeSelection(options, "chrome-extension");
|
|
7797
8152
|
let pkgList = directResult.components || [];
|
|
7798
8153
|
if (directResult.extensionDirs?.length) {
|
|
7799
8154
|
sourcePaths = directResult.extensionDirs.slice();
|
|
@@ -7812,20 +8167,23 @@ export async function createChromeExtensionBom(path, options) {
|
|
|
7812
8167
|
`Found ${pkgList.length} component(s) from direct Chrome extension path scan`,
|
|
7813
8168
|
);
|
|
7814
8169
|
}
|
|
7815
|
-
if (
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
8170
|
+
if (shouldDiscoverInstalledChromeExtensions) {
|
|
8171
|
+
const chromeDirs = discoverChromiumExtensionDirs();
|
|
8172
|
+
if (chromeDirs.length) {
|
|
8173
|
+
if (DEBUG_MODE) {
|
|
8174
|
+
thoughtLog(
|
|
8175
|
+
`Discovered Chromium extension directories: ${chromeDirs.map((d) => `${d.browser} (${d.channel}): ${d.dir}`).join(", ")}`,
|
|
8176
|
+
);
|
|
8177
|
+
}
|
|
8178
|
+
if (!pkgList.length) {
|
|
8179
|
+
pkgList = collectInstalledChromeExtensions(chromeDirs);
|
|
8180
|
+
sourcePaths = chromeDirs.map((d) => d.dir);
|
|
8181
|
+
}
|
|
8182
|
+
if (DEBUG_MODE && pkgList.length && !directResult.components?.length) {
|
|
8183
|
+
thoughtLog(
|
|
8184
|
+
`Found ${pkgList.length} Chrome/Chromium extension(s) from ${chromeDirs.length} browser location(s)`,
|
|
8185
|
+
);
|
|
8186
|
+
}
|
|
7829
8187
|
}
|
|
7830
8188
|
}
|
|
7831
8189
|
pkgList = trimComponents(pkgList);
|
|
@@ -7945,6 +8303,26 @@ export async function createCryptoCertsBom(path, options) {
|
|
|
7945
8303
|
for (const f of certFiles) {
|
|
7946
8304
|
const name = basename(f);
|
|
7947
8305
|
const fileHash = await checksumFile("sha256", f);
|
|
8306
|
+
let evidence;
|
|
8307
|
+
if (options.evidence) {
|
|
8308
|
+
const identityEvidence = {
|
|
8309
|
+
field: "name",
|
|
8310
|
+
confidence: 1,
|
|
8311
|
+
concludedValue: name,
|
|
8312
|
+
methods: [
|
|
8313
|
+
{
|
|
8314
|
+
technique: "filename",
|
|
8315
|
+
confidence: 1,
|
|
8316
|
+
value: f,
|
|
8317
|
+
},
|
|
8318
|
+
],
|
|
8319
|
+
};
|
|
8320
|
+
evidence = {
|
|
8321
|
+
identity:
|
|
8322
|
+
options.specVersion >= 1.6 ? [identityEvidence] : identityEvidence,
|
|
8323
|
+
occurrences: [{ location: f }],
|
|
8324
|
+
};
|
|
8325
|
+
}
|
|
7948
8326
|
const apkg = {
|
|
7949
8327
|
name,
|
|
7950
8328
|
type: "cryptographic-asset",
|
|
@@ -7957,10 +8335,18 @@ export async function createCryptoCertsBom(path, options) {
|
|
|
7957
8335
|
implementationPlatform: "unknown",
|
|
7958
8336
|
},
|
|
7959
8337
|
},
|
|
8338
|
+
...(evidence ? { evidence } : {}),
|
|
7960
8339
|
properties: [{ name: "SrcFile", value: f }],
|
|
7961
8340
|
};
|
|
7962
8341
|
pkgList.push(apkg);
|
|
7963
8342
|
}
|
|
8343
|
+
const sourceCryptoComponents = await collectSourceCryptoComponents(
|
|
8344
|
+
path,
|
|
8345
|
+
options,
|
|
8346
|
+
);
|
|
8347
|
+
if (sourceCryptoComponents.length) {
|
|
8348
|
+
pkgList.push(...sourceCryptoComponents);
|
|
8349
|
+
}
|
|
7964
8350
|
return {
|
|
7965
8351
|
bomJson: {
|
|
7966
8352
|
components: pkgList,
|
|
@@ -8051,6 +8437,7 @@ export async function createMultiXBom(pathList, options) {
|
|
|
8051
8437
|
) {
|
|
8052
8438
|
const {
|
|
8053
8439
|
osPackages,
|
|
8440
|
+
osPackageFiles,
|
|
8054
8441
|
dependenciesList,
|
|
8055
8442
|
allTypes,
|
|
8056
8443
|
bundledSdks,
|
|
@@ -8058,6 +8445,8 @@ export async function createMultiXBom(pathList, options) {
|
|
|
8058
8445
|
binPaths,
|
|
8059
8446
|
executables,
|
|
8060
8447
|
sharedLibs,
|
|
8448
|
+
services,
|
|
8449
|
+
tools,
|
|
8061
8450
|
} = await getOSPackages(
|
|
8062
8451
|
options.allLayersExplodedDir,
|
|
8063
8452
|
options.exportData?.inspectData?.Config,
|
|
@@ -8067,14 +8456,16 @@ export async function createMultiXBom(pathList, options) {
|
|
|
8067
8456
|
options.bundledSdks = bundledSdks;
|
|
8068
8457
|
options.bundledRuntimes = bundledRuntimes;
|
|
8069
8458
|
options.binPaths = binPaths;
|
|
8459
|
+
options.unpackagedExecutableCount = executables?.length || 0;
|
|
8460
|
+
options.unpackagedSharedLibraryCount = sharedLibs?.length || 0;
|
|
8070
8461
|
if (DEBUG_MODE) {
|
|
8071
8462
|
console.log(
|
|
8072
|
-
`**OS**: Found ${osPackages.length} OS packages, ${executables?.length} executables,
|
|
8463
|
+
`**OS**: Found ${osPackages.length} OS packages, ${osPackageFiles?.length} package-owned files, ${executables?.length} unpackaged executables, ${sharedLibs.length} unpackaged shared libraries, and ${services?.length || 0} packaged services at ${options.allLayersExplodedDir}`,
|
|
8073
8464
|
);
|
|
8074
8465
|
}
|
|
8075
8466
|
if (osPackages.length) {
|
|
8076
8467
|
thoughtLog(
|
|
8077
|
-
`I found ${osPackages.length} OS packages and ${
|
|
8468
|
+
`I found ${osPackages.length} OS packages, ${osPackageFiles?.length || 0} package-owned files, and ${services?.length || 0} packaged services at ${options.allLayersExplodedDir}`,
|
|
8078
8469
|
);
|
|
8079
8470
|
} else if (executables?.length || sharedLibs?.length) {
|
|
8080
8471
|
thoughtLog(
|
|
@@ -8088,15 +8479,28 @@ export async function createMultiXBom(pathList, options) {
|
|
|
8088
8479
|
if (allTypes?.length) {
|
|
8089
8480
|
options.allOSComponentTypes = allTypes;
|
|
8090
8481
|
}
|
|
8482
|
+
if (tools?.length) {
|
|
8483
|
+
options.tools = (
|
|
8484
|
+
Array.isArray(options.tools)
|
|
8485
|
+
? options.tools
|
|
8486
|
+
: options.tools?.components || []
|
|
8487
|
+
).concat(tools);
|
|
8488
|
+
}
|
|
8091
8489
|
components = components.concat(osPackages);
|
|
8490
|
+
components = components.concat(osPackageFiles || []);
|
|
8092
8491
|
components = components.concat(executables);
|
|
8093
8492
|
components = components.concat(sharedLibs);
|
|
8094
8493
|
if (dependenciesList?.length) {
|
|
8095
8494
|
dependencies = mergeDependencies(dependencies, dependenciesList);
|
|
8096
8495
|
}
|
|
8496
|
+
if (services?.length) {
|
|
8497
|
+
options.services = mergeServices(options.services || [], services);
|
|
8498
|
+
}
|
|
8097
8499
|
if (parentComponent && Object.keys(parentComponent).length) {
|
|
8098
8500
|
// Make the parent oci image depend on all os components
|
|
8099
|
-
const parentDependsOn = new Set(
|
|
8501
|
+
const parentDependsOn = new Set(
|
|
8502
|
+
osPackages.concat(osPackageFiles || []).map((p) => p["bom-ref"]),
|
|
8503
|
+
);
|
|
8100
8504
|
dependencies.splice(0, 0, {
|
|
8101
8505
|
ref: parentComponent["bom-ref"],
|
|
8102
8506
|
dependsOn: Array.from(parentDependsOn).sort(),
|
|
@@ -8798,6 +9202,28 @@ export async function createMultiXBom(pathList, options) {
|
|
|
8798
9202
|
}
|
|
8799
9203
|
}
|
|
8800
9204
|
}
|
|
9205
|
+
if (hasAnyProjectType(["asar"], options)) {
|
|
9206
|
+
setProjectTypeActivityContext("asar", path);
|
|
9207
|
+
bomData = await createAsarBom(path, options);
|
|
9208
|
+
if (bomData?.bomJson?.components?.length) {
|
|
9209
|
+
if (DEBUG_MODE) {
|
|
9210
|
+
console.log(
|
|
9211
|
+
`Found ${bomData.bomJson.components.length} ASAR component(s) at ${path}`,
|
|
9212
|
+
);
|
|
9213
|
+
}
|
|
9214
|
+
components = components.concat(bomData.bomJson.components);
|
|
9215
|
+
dependencies = mergeDependencies(
|
|
9216
|
+
dependencies,
|
|
9217
|
+
bomData.bomJson.dependencies,
|
|
9218
|
+
);
|
|
9219
|
+
if (
|
|
9220
|
+
bomData.parentComponent &&
|
|
9221
|
+
Object.keys(bomData.parentComponent).length
|
|
9222
|
+
) {
|
|
9223
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
9224
|
+
}
|
|
9225
|
+
}
|
|
9226
|
+
}
|
|
8801
9227
|
if (hasAnyProjectType(["vscode-extension"], options)) {
|
|
8802
9228
|
setProjectTypeActivityContext("vscode-extension", path);
|
|
8803
9229
|
bomData = await createVscodeExtensionBom(path, options);
|
|
@@ -9162,6 +9588,11 @@ export async function createXBom(path, options) {
|
|
|
9162
9588
|
`${options.multiProject ? "**/" : ""}conan.lock`,
|
|
9163
9589
|
options,
|
|
9164
9590
|
);
|
|
9591
|
+
const colliderLockFiles = getAllFiles(
|
|
9592
|
+
path,
|
|
9593
|
+
`${options.multiProject ? "**/" : ""}collider.lock`,
|
|
9594
|
+
options,
|
|
9595
|
+
);
|
|
9165
9596
|
const conanFiles = getAllFiles(
|
|
9166
9597
|
path,
|
|
9167
9598
|
`${options.multiProject ? "**/" : ""}conanfile.txt`,
|
|
@@ -9178,6 +9609,7 @@ export async function createXBom(path, options) {
|
|
|
9178
9609
|
options,
|
|
9179
9610
|
);
|
|
9180
9611
|
if (
|
|
9612
|
+
colliderLockFiles.length ||
|
|
9181
9613
|
conanLockFiles.length ||
|
|
9182
9614
|
conanFiles.length ||
|
|
9183
9615
|
cmakeListFiles.length ||
|
|
@@ -9231,6 +9663,16 @@ export async function createXBom(path, options) {
|
|
|
9231
9663
|
return await createVscodeExtensionBom(path, options);
|
|
9232
9664
|
}
|
|
9233
9665
|
|
|
9666
|
+
// Electron ASAR archives
|
|
9667
|
+
const asarFiles = getAllFiles(
|
|
9668
|
+
path,
|
|
9669
|
+
`${options.multiProject ? "**/" : ""}*.asar`,
|
|
9670
|
+
options,
|
|
9671
|
+
);
|
|
9672
|
+
if (asarFiles.length) {
|
|
9673
|
+
return await createAsarBom(path, options);
|
|
9674
|
+
}
|
|
9675
|
+
|
|
9234
9676
|
// Helm charts
|
|
9235
9677
|
const chartFiles = getAllFiles(
|
|
9236
9678
|
path,
|
|
@@ -9333,6 +9775,35 @@ export async function createXBom(path, options) {
|
|
|
9333
9775
|
}
|
|
9334
9776
|
}
|
|
9335
9777
|
|
|
9778
|
+
/**
|
|
9779
|
+
* Function to create a hardware BOM for the current host.
|
|
9780
|
+
*
|
|
9781
|
+
* @param {string} _path Source path (unused for live host HBOM generation)
|
|
9782
|
+
* @param {Object} options Parse options from the cli
|
|
9783
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
9784
|
+
*/
|
|
9785
|
+
export async function createHBom(_path, options) {
|
|
9786
|
+
ensureHbomRuntimeSupport(options, options.commandName || "hbom");
|
|
9787
|
+
let bomJson = await createHbomDocument(options);
|
|
9788
|
+
if (options.includeRuntime) {
|
|
9789
|
+
const runtimeOptions = {
|
|
9790
|
+
...options,
|
|
9791
|
+
includeRuntime: false,
|
|
9792
|
+
multiProject: false,
|
|
9793
|
+
projectType: ["os"],
|
|
9794
|
+
};
|
|
9795
|
+
const obomData = await createOSBom(_path, runtimeOptions);
|
|
9796
|
+
bomJson = mergeHostInventoryBoms(bomJson, obomData);
|
|
9797
|
+
} else {
|
|
9798
|
+
bomJson = mergeHostInventoryBoms(bomJson);
|
|
9799
|
+
}
|
|
9800
|
+
return {
|
|
9801
|
+
bomJson,
|
|
9802
|
+
dependencies: bomJson.dependencies || [],
|
|
9803
|
+
parentComponent: bomJson.metadata?.component,
|
|
9804
|
+
};
|
|
9805
|
+
}
|
|
9806
|
+
|
|
9336
9807
|
/**
|
|
9337
9808
|
* Function to create bom string for various languages
|
|
9338
9809
|
*
|
|
@@ -9345,8 +9816,27 @@ export async function createBom(path, options) {
|
|
|
9345
9816
|
if (!projectType) {
|
|
9346
9817
|
projectType = [];
|
|
9347
9818
|
}
|
|
9819
|
+
ensureNoMixedHbomProjectTypes(projectType);
|
|
9820
|
+
if (hasHbomProjectType(projectType)) {
|
|
9821
|
+
const selectedHbomProjectType = Array.isArray(projectType)
|
|
9822
|
+
? projectType[0]
|
|
9823
|
+
: `${projectType}`.split(",")[0];
|
|
9824
|
+
options.projectType = [selectedHbomProjectType];
|
|
9825
|
+
setActivityContext({
|
|
9826
|
+
projectType: selectedHbomProjectType,
|
|
9827
|
+
sourcePath: path,
|
|
9828
|
+
});
|
|
9829
|
+
thoughtLog(
|
|
9830
|
+
"The user wants a Hardware Bill-of-Materials (HBOM) for the current host. Let's use the dedicated hardware collector.",
|
|
9831
|
+
);
|
|
9832
|
+
return await createHBom(path, options);
|
|
9833
|
+
}
|
|
9348
9834
|
let exportData;
|
|
9349
9835
|
let isContainerMode = false;
|
|
9836
|
+
const isLocalDirectoryInput =
|
|
9837
|
+
!options.projectType?.includes("universal") &&
|
|
9838
|
+
safeExistsSync(path) &&
|
|
9839
|
+
lstatSync(path).isDirectory();
|
|
9350
9840
|
// Docker and image archive support
|
|
9351
9841
|
// TODO: Support any source archive
|
|
9352
9842
|
if (path.endsWith(".tar") || path.endsWith(".tar.gz")) {
|
|
@@ -9359,6 +9849,22 @@ export async function createBom(path, options) {
|
|
|
9359
9849
|
return {};
|
|
9360
9850
|
}
|
|
9361
9851
|
isContainerMode = true;
|
|
9852
|
+
} else if (
|
|
9853
|
+
isLocalDirectoryInput &&
|
|
9854
|
+
(hasAnyProjectType(["oci-dir"], options, false) ||
|
|
9855
|
+
hasAnyProjectType(["oci"], options, false))
|
|
9856
|
+
) {
|
|
9857
|
+
isContainerMode = true;
|
|
9858
|
+
exportData = {
|
|
9859
|
+
inspectData: undefined,
|
|
9860
|
+
lastWorkingDir: "",
|
|
9861
|
+
allLayersDir: path,
|
|
9862
|
+
allLayersExplodedDir: path,
|
|
9863
|
+
};
|
|
9864
|
+
if (safeExistsSync(join(path, "all-layers"))) {
|
|
9865
|
+
exportData.allLayersExplodedDir = join(path, "all-layers");
|
|
9866
|
+
}
|
|
9867
|
+
exportData.pkgPathList = getPkgPathList(exportData, undefined);
|
|
9362
9868
|
} else if (
|
|
9363
9869
|
(options.projectType &&
|
|
9364
9870
|
!options.projectType?.includes("universal") &&
|
|
@@ -9386,21 +9892,6 @@ export async function createBom(path, options) {
|
|
|
9386
9892
|
console.log(path, "doesn't appear to be a valid container image.");
|
|
9387
9893
|
}
|
|
9388
9894
|
}
|
|
9389
|
-
} else if (
|
|
9390
|
-
!options.projectType?.includes("universal") &&
|
|
9391
|
-
hasAnyProjectType(["oci-dir"], options, false)
|
|
9392
|
-
) {
|
|
9393
|
-
isContainerMode = true;
|
|
9394
|
-
exportData = {
|
|
9395
|
-
inspectData: undefined,
|
|
9396
|
-
lastWorkingDir: "",
|
|
9397
|
-
allLayersDir: path,
|
|
9398
|
-
allLayersExplodedDir: path,
|
|
9399
|
-
};
|
|
9400
|
-
if (safeExistsSync(join(path, "all-layers"))) {
|
|
9401
|
-
exportData.allLayersDir = join(path, "all-layers");
|
|
9402
|
-
}
|
|
9403
|
-
exportData.pkgPathList = getPkgPathList(exportData, undefined);
|
|
9404
9895
|
}
|
|
9405
9896
|
if (isContainerMode) {
|
|
9406
9897
|
options.multiProject = true;
|
|
@@ -9474,6 +9965,9 @@ export async function createBom(path, options) {
|
|
|
9474
9965
|
if (path.endsWith(".war")) {
|
|
9475
9966
|
projectType = ["java"];
|
|
9476
9967
|
}
|
|
9968
|
+
if (!projectType.length && path.endsWith(".asar")) {
|
|
9969
|
+
projectType = ["asar"];
|
|
9970
|
+
}
|
|
9477
9971
|
if (projectType.length > 1) {
|
|
9478
9972
|
setActivityContext({
|
|
9479
9973
|
projectType: projectType.join(","),
|
|
@@ -9597,6 +10091,9 @@ export async function createBom(path, options) {
|
|
|
9597
10091
|
if (PROJECT_TYPE_ALIASES["caxa"].includes(projectType[0])) {
|
|
9598
10092
|
return await createCaxaBom(path, options);
|
|
9599
10093
|
}
|
|
10094
|
+
if (PROJECT_TYPE_ALIASES["asar"].includes(projectType[0])) {
|
|
10095
|
+
return await createAsarBom(path, options);
|
|
10096
|
+
}
|
|
9600
10097
|
if (PROJECT_TYPE_ALIASES["vscode-extension"].includes(projectType[0])) {
|
|
9601
10098
|
return await createVscodeExtensionBom(path, options);
|
|
9602
10099
|
}
|
|
@@ -9641,17 +10138,33 @@ export async function createBom(path, options) {
|
|
|
9641
10138
|
* @throws {Error} if the request fails
|
|
9642
10139
|
*/
|
|
9643
10140
|
export async function submitBom(args, bomContents) {
|
|
10141
|
+
const dependencyTrackApiUrl = getDependencyTrackBomApiUrl(args.serverUrl);
|
|
10142
|
+
const serverUrl = dependencyTrackApiUrl?.toString();
|
|
10143
|
+
if (!dependencyTrackApiUrl || !serverUrl) {
|
|
10144
|
+
console.log(
|
|
10145
|
+
"Invalid Dependency-Track server URL. Provide an absolute http(s) URL without dangerous characters.",
|
|
10146
|
+
);
|
|
10147
|
+
args.failOnError && process.exit(1);
|
|
10148
|
+
return undefined;
|
|
10149
|
+
}
|
|
10150
|
+
const serverHost = dependencyTrackApiUrl.hostname;
|
|
10151
|
+
if (!isAllowedHttpHost(serverHost)) {
|
|
10152
|
+
console.log(
|
|
10153
|
+
`Dependency-Track server host '${serverHost}' is not allowed by CDXGEN_ALLOWED_HOSTS.`,
|
|
10154
|
+
);
|
|
10155
|
+
args.failOnError && process.exit(1);
|
|
10156
|
+
return undefined;
|
|
10157
|
+
}
|
|
9644
10158
|
if (isDryRun) {
|
|
9645
10159
|
recordActivity({
|
|
9646
10160
|
kind: "network",
|
|
9647
10161
|
reason:
|
|
9648
10162
|
"Dry run mode blocks Dependency-Track submission and reports the request instead.",
|
|
9649
10163
|
status: "blocked",
|
|
9650
|
-
target:
|
|
10164
|
+
target: serverUrl,
|
|
9651
10165
|
});
|
|
9652
10166
|
return undefined;
|
|
9653
10167
|
}
|
|
9654
|
-
const serverUrl = getDependencyTrackBomUrl(args.serverUrl);
|
|
9655
10168
|
const bomPayload = buildDependencyTrackBomPayload(args, bomContents);
|
|
9656
10169
|
if (!bomPayload) {
|
|
9657
10170
|
console.log(
|
|
@@ -9670,27 +10183,31 @@ export async function submitBom(args, bomContents) {
|
|
|
9670
10183
|
);
|
|
9671
10184
|
}
|
|
9672
10185
|
try {
|
|
9673
|
-
|
|
9674
|
-
console.log(
|
|
9675
|
-
"Calling ",
|
|
9676
|
-
serverUrl,
|
|
9677
|
-
"with --skip-dt-tls-check argument: Skip DT TLS check.",
|
|
9678
|
-
);
|
|
9679
|
-
}
|
|
9680
|
-
// See issue #1963 regarding CRLF hardening
|
|
9681
|
-
return await got(serverUrl, {
|
|
10186
|
+
const requestOptions = {
|
|
9682
10187
|
method: "PUT",
|
|
10188
|
+
followRedirect: false,
|
|
9683
10189
|
https: {
|
|
9684
10190
|
rejectUnauthorized: !args.skipDtTlsCheck,
|
|
9685
10191
|
},
|
|
9686
10192
|
headers: {
|
|
9687
10193
|
"X-Api-Key": (args.apiKey || "").replace(/[\r\n]/g, ""),
|
|
9688
10194
|
"Content-Type": "application/json",
|
|
9689
|
-
"user-agent": `@CycloneDX/cdxgen ${CDXGEN_VERSION}`,
|
|
9690
10195
|
},
|
|
9691
10196
|
json: bomPayload,
|
|
9692
10197
|
responseType: "json",
|
|
9693
|
-
|
|
10198
|
+
context: {
|
|
10199
|
+
activityIntent: "bom-submit",
|
|
10200
|
+
},
|
|
10201
|
+
};
|
|
10202
|
+
if (DEBUG_MODE && args.skipDtTlsCheck) {
|
|
10203
|
+
console.log(
|
|
10204
|
+
"Calling ",
|
|
10205
|
+
serverUrl,
|
|
10206
|
+
"with --skip-dt-tls-check argument: Skip DT TLS check.",
|
|
10207
|
+
);
|
|
10208
|
+
}
|
|
10209
|
+
// See issue #1963 regarding CRLF hardening
|
|
10210
|
+
return await cdxgenAgent(dependencyTrackApiUrl, requestOptions).json();
|
|
9694
10211
|
} catch (error) {
|
|
9695
10212
|
if (error.response && error.response.statusCode === 401) {
|
|
9696
10213
|
// Unauthorized
|
|
@@ -9703,18 +10220,21 @@ export async function submitBom(args, bomContents) {
|
|
|
9703
10220
|
);
|
|
9704
10221
|
// Method not allowed errors
|
|
9705
10222
|
try {
|
|
9706
|
-
return await
|
|
10223
|
+
return await cdxgenAgent(dependencyTrackApiUrl, {
|
|
9707
10224
|
method: "POST",
|
|
10225
|
+
followRedirect: false,
|
|
9708
10226
|
https: {
|
|
9709
10227
|
rejectUnauthorized: !args.skipDtTlsCheck,
|
|
9710
10228
|
},
|
|
9711
10229
|
headers: {
|
|
9712
|
-
"X-Api-Key": args.apiKey,
|
|
10230
|
+
"X-Api-Key": (args.apiKey || "").replace(/[\r\n]/g, ""),
|
|
9713
10231
|
"Content-Type": "application/json",
|
|
9714
|
-
"user-agent": `@CycloneDX/cdxgen ${CDXGEN_VERSION}`,
|
|
9715
10232
|
},
|
|
9716
10233
|
json: bomPayload,
|
|
9717
10234
|
responseType: "json",
|
|
10235
|
+
context: {
|
|
10236
|
+
activityIntent: "bom-submit",
|
|
10237
|
+
},
|
|
9718
10238
|
}).json();
|
|
9719
10239
|
} catch (error) {
|
|
9720
10240
|
if (DEBUG_MODE) {
|