@cyclonedx/cdxgen 12.2.0 → 12.3.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 +242 -90
- package/bin/audit.js +191 -0
- package/bin/cdxgen.js +532 -168
- package/bin/convert.js +99 -0
- package/bin/evinse.js +23 -0
- package/bin/repl.js +339 -8
- package/bin/sign.js +8 -0
- package/bin/validate.js +8 -0
- package/bin/verify.js +8 -0
- package/data/container-knowledge-index.json +125 -0
- package/data/gtfobins-index.json +6296 -0
- package/data/lolbas-index.json +150 -0
- package/data/queries-darwin.json +63 -3
- package/data/queries-win.json +45 -3
- package/data/queries.json +74 -2
- package/data/rules/chrome-extensions.yaml +240 -0
- package/data/rules/ci-permissions.yaml +478 -18
- package/data/rules/container-risk.yaml +270 -0
- package/data/rules/obom-runtime.yaml +891 -0
- package/data/rules/package-integrity.yaml +49 -0
- package/data/spdx-export.schema.json +6794 -0
- package/data/spdx-model-v3.0.1.jsonld +15999 -0
- package/lib/audit/index.js +1924 -0
- package/lib/audit/index.poku.js +1488 -0
- package/lib/audit/progress.js +137 -0
- package/lib/audit/progress.poku.js +188 -0
- package/lib/audit/reporters.js +618 -0
- package/lib/audit/scoring.js +310 -0
- package/lib/audit/scoring.poku.js +341 -0
- package/lib/audit/targets.js +260 -0
- package/lib/audit/targets.poku.js +331 -0
- package/lib/cli/index.js +276 -68
- package/lib/cli/index.poku.js +368 -0
- package/lib/helpers/analyzer.js +1052 -5
- package/lib/helpers/analyzer.poku.js +301 -0
- package/lib/helpers/annotationFormatter.js +49 -0
- package/lib/helpers/annotationFormatter.poku.js +44 -0
- package/lib/helpers/bomUtils.js +36 -0
- package/lib/helpers/bomUtils.poku.js +51 -0
- package/lib/helpers/caxa.js +2 -2
- package/lib/helpers/chromextutils.js +1153 -0
- package/lib/helpers/chromextutils.poku.js +493 -0
- package/lib/helpers/ciParsers/githubActions.js +1632 -45
- package/lib/helpers/ciParsers/githubActions.poku.js +853 -1
- package/lib/helpers/containerRisk.js +186 -0
- package/lib/helpers/containerRisk.poku.js +52 -0
- package/lib/helpers/depsUtils.js +16 -0
- package/lib/helpers/depsUtils.poku.js +58 -1
- package/lib/helpers/display.js +245 -61
- package/lib/helpers/display.poku.js +162 -2
- package/lib/helpers/exportUtils.js +123 -0
- package/lib/helpers/exportUtils.poku.js +60 -0
- package/lib/helpers/formulationParsers.js +69 -0
- package/lib/helpers/formulationParsers.poku.js +44 -0
- package/lib/helpers/gtfobins.js +189 -0
- package/lib/helpers/gtfobins.poku.js +49 -0
- package/lib/helpers/lolbas.js +267 -0
- package/lib/helpers/lolbas.poku.js +39 -0
- package/lib/helpers/osqueryTransform.js +84 -0
- package/lib/helpers/osqueryTransform.poku.js +49 -0
- package/lib/helpers/provenanceUtils.js +193 -0
- package/lib/helpers/provenanceUtils.poku.js +145 -0
- package/lib/helpers/pylockutils.js +281 -0
- package/lib/helpers/pylockutils.poku.js +48 -0
- package/lib/helpers/registryProvenance.js +793 -0
- package/lib/helpers/registryProvenance.poku.js +452 -0
- package/lib/helpers/remote/dependency-track.js +84 -0
- package/lib/helpers/remote/dependency-track.poku.js +119 -0
- package/lib/helpers/source.js +1267 -0
- package/lib/helpers/source.poku.js +771 -0
- package/lib/helpers/spdxUtils.js +97 -0
- package/lib/helpers/spdxUtils.poku.js +70 -0
- package/lib/helpers/table.js +384 -0
- package/lib/helpers/table.poku.js +186 -0
- package/lib/helpers/unicodeScan.js +147 -0
- package/lib/helpers/unicodeScan.poku.js +45 -0
- package/lib/helpers/utils.js +882 -136
- package/lib/helpers/utils.poku.js +995 -91
- package/lib/managers/binary.js +29 -5
- package/lib/managers/docker.js +179 -52
- package/lib/managers/docker.poku.js +327 -28
- package/lib/managers/oci.js +107 -23
- package/lib/managers/oci.poku.js +132 -0
- package/lib/server/openapi.yaml +50 -0
- package/lib/server/server.js +228 -331
- package/lib/server/server.poku.js +220 -5
- package/lib/stages/postgen/annotator.js +7 -0
- package/lib/stages/postgen/annotator.poku.js +40 -0
- package/lib/stages/postgen/auditBom.js +20 -5
- package/lib/stages/postgen/auditBom.poku.js +1729 -67
- package/lib/stages/postgen/postgen.js +40 -0
- package/lib/stages/postgen/postgen.poku.js +47 -0
- package/lib/stages/postgen/ruleEngine.js +80 -2
- package/lib/stages/postgen/spdxConverter.js +796 -0
- package/lib/stages/postgen/spdxConverter.poku.js +341 -0
- package/lib/validator/bomValidator.js +232 -0
- package/lib/validator/bomValidator.poku.js +70 -0
- package/lib/validator/complianceRules.js +70 -7
- package/lib/validator/complianceRules.poku.js +30 -0
- package/lib/validator/reporters/annotations.js +2 -2
- package/lib/validator/reporters/console.js +13 -2
- package/lib/validator/reporters.poku.js +13 -0
- package/package.json +10 -8
- package/types/bin/audit.d.ts +3 -0
- package/types/bin/audit.d.ts.map +1 -0
- package/types/bin/convert.d.ts +3 -0
- package/types/bin/convert.d.ts.map +1 -0
- package/types/bin/repl.d.ts.map +1 -1
- package/types/lib/audit/index.d.ts +115 -0
- package/types/lib/audit/index.d.ts.map +1 -0
- package/types/lib/audit/progress.d.ts +27 -0
- package/types/lib/audit/progress.d.ts.map +1 -0
- package/types/lib/audit/reporters.d.ts +35 -0
- package/types/lib/audit/reporters.d.ts.map +1 -0
- package/types/lib/audit/scoring.d.ts +35 -0
- package/types/lib/audit/scoring.d.ts.map +1 -0
- package/types/lib/audit/targets.d.ts +63 -0
- package/types/lib/audit/targets.d.ts.map +1 -0
- package/types/lib/cli/index.d.ts +8 -0
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/helpers/analyzer.d.ts +13 -0
- package/types/lib/helpers/analyzer.d.ts.map +1 -1
- package/types/lib/helpers/annotationFormatter.d.ts +23 -0
- package/types/lib/helpers/annotationFormatter.d.ts.map +1 -0
- package/types/lib/helpers/bomUtils.d.ts +5 -0
- package/types/lib/helpers/bomUtils.d.ts.map +1 -0
- package/types/lib/helpers/chromextutils.d.ts +97 -0
- package/types/lib/helpers/chromextutils.d.ts.map +1 -0
- package/types/lib/helpers/ciParsers/githubActions.d.ts +3 -8
- package/types/lib/helpers/ciParsers/githubActions.d.ts.map +1 -1
- package/types/lib/helpers/containerRisk.d.ts +17 -0
- package/types/lib/helpers/containerRisk.d.ts.map +1 -0
- package/types/lib/helpers/depsUtils.d.ts.map +1 -1
- package/types/lib/helpers/display.d.ts +4 -1
- package/types/lib/helpers/display.d.ts.map +1 -1
- package/types/lib/helpers/exportUtils.d.ts +40 -0
- package/types/lib/helpers/exportUtils.d.ts.map +1 -0
- package/types/lib/helpers/formulationParsers.d.ts.map +1 -1
- package/types/lib/helpers/gtfobins.d.ts +17 -0
- package/types/lib/helpers/gtfobins.d.ts.map +1 -0
- package/types/lib/helpers/lolbas.d.ts +16 -0
- package/types/lib/helpers/lolbas.d.ts.map +1 -0
- package/types/lib/helpers/osqueryTransform.d.ts +7 -0
- package/types/lib/helpers/osqueryTransform.d.ts.map +1 -0
- package/types/lib/helpers/provenanceUtils.d.ts +90 -0
- package/types/lib/helpers/provenanceUtils.d.ts.map +1 -0
- package/types/lib/helpers/pylockutils.d.ts +51 -0
- package/types/lib/helpers/pylockutils.d.ts.map +1 -0
- package/types/lib/helpers/registryProvenance.d.ts +17 -0
- package/types/lib/helpers/registryProvenance.d.ts.map +1 -0
- package/types/lib/helpers/remote/dependency-track.d.ts +16 -0
- package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -0
- package/types/lib/helpers/source.d.ts +141 -0
- package/types/lib/helpers/source.d.ts.map +1 -0
- package/types/lib/helpers/spdxUtils.d.ts +2 -0
- package/types/lib/helpers/spdxUtils.d.ts.map +1 -0
- package/types/lib/helpers/table.d.ts +6 -0
- package/types/lib/helpers/table.d.ts.map +1 -0
- package/types/lib/helpers/unicodeScan.d.ts +46 -0
- package/types/lib/helpers/unicodeScan.d.ts.map +1 -0
- package/types/lib/helpers/utils.d.ts +30 -11
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/managers/binary.d.ts.map +1 -1
- package/types/lib/managers/docker.d.ts.map +1 -1
- package/types/lib/managers/oci.d.ts.map +1 -1
- package/types/lib/server/server.d.ts +0 -35
- 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.map +1 -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/postgen/spdxConverter.d.ts +11 -0
- package/types/lib/stages/postgen/spdxConverter.d.ts.map +1 -0
- package/types/lib/validator/bomValidator.d.ts +1 -0
- package/types/lib/validator/bomValidator.d.ts.map +1 -1
- package/types/lib/validator/complianceRules.d.ts.map +1 -1
- package/types/lib/validator/reporters/console.d.ts.map +1 -1
- package/types/bin/dependencies.d.ts +0 -3
- package/types/bin/dependencies.d.ts.map +0 -1
- package/types/bin/licenses.d.ts +0 -3
- package/types/bin/licenses.d.ts.map +0 -1
package/lib/cli/index.js
CHANGED
|
@@ -19,15 +19,26 @@ import got from "got";
|
|
|
19
19
|
import { PackageURL } from "packageurl-js";
|
|
20
20
|
import { gte, lte } from "semver";
|
|
21
21
|
import { parse } from "ssri";
|
|
22
|
-
import { table } from "table";
|
|
23
22
|
import { v4 as uuidv4 } from "uuid";
|
|
24
23
|
import { parse as loadYaml } from "yaml";
|
|
25
24
|
|
|
26
25
|
import { findJSImportsExports } from "../helpers/analyzer.js";
|
|
27
26
|
import { parseCaxaMetadata } from "../helpers/caxa.js";
|
|
27
|
+
import {
|
|
28
|
+
CHROME_EXTENSION_PURL_TYPE,
|
|
29
|
+
collectChromeExtensionsFromPath,
|
|
30
|
+
collectInstalledChromeExtensions,
|
|
31
|
+
discoverChromiumExtensionDirs,
|
|
32
|
+
} from "../helpers/chromextutils.js";
|
|
28
33
|
import { mergeDependencies, trimComponents } from "../helpers/depsUtils.js";
|
|
29
34
|
import { GIT_COMMAND } from "../helpers/envcontext.js";
|
|
30
35
|
import { thoughtLog } from "../helpers/logger.js";
|
|
36
|
+
import { isPyLockFile } from "../helpers/pylockutils.js";
|
|
37
|
+
import {
|
|
38
|
+
buildDependencyTrackBomPayload,
|
|
39
|
+
getDependencyTrackBomUrl,
|
|
40
|
+
} from "../helpers/remote/dependency-track.js";
|
|
41
|
+
import { table } from "../helpers/table.js";
|
|
31
42
|
import {
|
|
32
43
|
addEvidenceForDotnet,
|
|
33
44
|
addEvidenceForImports,
|
|
@@ -1252,7 +1263,7 @@ const buildBomNSData = (options, pkgInfo, ptype, context) => {
|
|
|
1252
1263
|
// CycloneDX Json Template
|
|
1253
1264
|
const jsonTpl = {
|
|
1254
1265
|
bomFormat: "CycloneDX",
|
|
1255
|
-
specVersion: `${options.specVersion || "1.
|
|
1266
|
+
specVersion: `${options.specVersion || "1.7"}`,
|
|
1256
1267
|
serialNumber: serialNum,
|
|
1257
1268
|
version: 1,
|
|
1258
1269
|
metadata: metadata,
|
|
@@ -1490,6 +1501,8 @@ export async function createJavaBom(path, options) {
|
|
|
1490
1501
|
}
|
|
1491
1502
|
let result;
|
|
1492
1503
|
let mvnArgs;
|
|
1504
|
+
// FIXME: How do we motivate everyone to upgrade to 1.7?
|
|
1505
|
+
const toolsSpecVersion = 1.6;
|
|
1493
1506
|
if (isQuarkus) {
|
|
1494
1507
|
thoughtLog(
|
|
1495
1508
|
"This appears to be a Quarkus project. Let's use the right Maven plugin.",
|
|
@@ -1500,12 +1513,14 @@ export async function createJavaBom(path, options) {
|
|
|
1500
1513
|
"quarkus:dependency-sbom",
|
|
1501
1514
|
"-Dquarkus.analytics.disabled=true",
|
|
1502
1515
|
];
|
|
1503
|
-
if (options.specVersion) {
|
|
1516
|
+
if (options.specVersion >= 1.6) {
|
|
1504
1517
|
mvnArgs = mvnArgs.concat(
|
|
1505
|
-
`-Dquarkus.dependency.sbom.schema-version=${
|
|
1518
|
+
`-Dquarkus.dependency.sbom.schema-version=${toolsSpecVersion}`,
|
|
1506
1519
|
);
|
|
1507
1520
|
}
|
|
1508
1521
|
} else {
|
|
1522
|
+
// FIXME: The last maven plugin release was on November 28th, 2024.
|
|
1523
|
+
// Should we fork this repo and maintain it ourselves?
|
|
1509
1524
|
const cdxMavenPlugin =
|
|
1510
1525
|
process.env.CDX_MAVEN_PLUGIN ||
|
|
1511
1526
|
"org.cyclonedx:cyclonedx-maven-plugin:2.9.1";
|
|
@@ -1527,9 +1542,11 @@ export async function createJavaBom(path, options) {
|
|
|
1527
1542
|
const addArgs = process.env.MVN_ARGS.split(" ");
|
|
1528
1543
|
mvnArgs = mvnArgs.concat(addArgs);
|
|
1529
1544
|
}
|
|
1530
|
-
// specVersion 1.4 doesn't support externalReferences.type=
|
|
1545
|
+
// specVersion 1.4 doesn't support externalReferences.type=distribution-intake
|
|
1531
1546
|
// so we need to run the plugin with the correct version
|
|
1532
|
-
if (options.specVersion) {
|
|
1547
|
+
if (options.specVersion >= 1.6) {
|
|
1548
|
+
mvnArgs = mvnArgs.concat(`-DschemaVersion=${toolsSpecVersion}`);
|
|
1549
|
+
} else if (options.specVersion > 1.4) {
|
|
1533
1550
|
mvnArgs = mvnArgs.concat(`-DschemaVersion=${options.specVersion}`);
|
|
1534
1551
|
}
|
|
1535
1552
|
}
|
|
@@ -2723,6 +2740,21 @@ export async function createNodejsBom(path, options) {
|
|
|
2723
2740
|
`${options.multiProject ? "**/" : ""}bower.json`,
|
|
2724
2741
|
options,
|
|
2725
2742
|
);
|
|
2743
|
+
if (DEBUG_MODE) {
|
|
2744
|
+
const wasmFiles = getAllFiles(
|
|
2745
|
+
path,
|
|
2746
|
+
`${options.multiProject ? "**/" : ""}*.wasm`,
|
|
2747
|
+
{
|
|
2748
|
+
...options,
|
|
2749
|
+
includeNodeModulesDir: true,
|
|
2750
|
+
},
|
|
2751
|
+
);
|
|
2752
|
+
if (wasmFiles?.length) {
|
|
2753
|
+
console.log(
|
|
2754
|
+
`Found ${wasmFiles.length} wasm files in this project. cdxgen will make a best attempt to identify the exports and imports from these files.`,
|
|
2755
|
+
);
|
|
2756
|
+
}
|
|
2757
|
+
}
|
|
2726
2758
|
// Parse min js files
|
|
2727
2759
|
if (minJsFiles?.length) {
|
|
2728
2760
|
manifestFiles = manifestFiles.concat(minJsFiles);
|
|
@@ -2994,7 +3026,7 @@ export async function createNodejsBom(path, options) {
|
|
|
2994
3026
|
if (!wpkgJsonFiles?.length) {
|
|
2995
3027
|
if (!workspaceWarningShown) {
|
|
2996
3028
|
workspaceWarningShown = true;
|
|
2997
|
-
console.
|
|
3029
|
+
console.warn(
|
|
2998
3030
|
`Unable to find any package.json files belonging to the workspace '${awp}' referred in ${f}. To improve SBOM precision, run cdxgen from the directory containing the complete source code.`,
|
|
2999
3031
|
);
|
|
3000
3032
|
}
|
|
@@ -3084,7 +3116,7 @@ export async function createNodejsBom(path, options) {
|
|
|
3084
3116
|
}
|
|
3085
3117
|
if (!Object.keys(parentComponent).length) {
|
|
3086
3118
|
if (safeExistsSync(packageJsonF)) {
|
|
3087
|
-
const pcs = await parsePkgJson(packageJsonF, true);
|
|
3119
|
+
const pcs = await parsePkgJson(packageJsonF, true, true);
|
|
3088
3120
|
if (pcs.length && Object.keys(pcs[0]).length) {
|
|
3089
3121
|
parentComponent = { ...pcs[0] };
|
|
3090
3122
|
parentComponent.type = "application";
|
|
@@ -3170,7 +3202,7 @@ export async function createNodejsBom(path, options) {
|
|
|
3170
3202
|
const basePath = dirname(f);
|
|
3171
3203
|
const packageJsonF = join(basePath, "package.json");
|
|
3172
3204
|
if (safeExistsSync(packageJsonF)) {
|
|
3173
|
-
const pcs = await parsePkgJson(packageJsonF, true);
|
|
3205
|
+
const pcs = await parsePkgJson(packageJsonF, true, true);
|
|
3174
3206
|
if (pcs.length && Object.keys(pcs[0]).length) {
|
|
3175
3207
|
tmpParentComponent = { ...pcs[0] };
|
|
3176
3208
|
tmpParentComponent.type = "application";
|
|
@@ -3242,6 +3274,7 @@ export async function createNodejsBom(path, options) {
|
|
|
3242
3274
|
const pnpmLock = join(path, "common", "config", "rush", "pnpm-lock.yaml");
|
|
3243
3275
|
if (safeExistsSync(swFile)) {
|
|
3244
3276
|
let pkgList = await parseNodeShrinkwrap(swFile);
|
|
3277
|
+
pkgList = addWasmComponentsFromImports(pkgList, allImports);
|
|
3245
3278
|
if (allImports && Object.keys(allImports).length) {
|
|
3246
3279
|
pkgList = await addEvidenceForImports(
|
|
3247
3280
|
pkgList,
|
|
@@ -3258,9 +3291,13 @@ export async function createNodejsBom(path, options) {
|
|
|
3258
3291
|
}
|
|
3259
3292
|
if (safeExistsSync(pnpmLock)) {
|
|
3260
3293
|
const pnpmLockObj = await parsePnpmLock(pnpmLock);
|
|
3294
|
+
let pkgList = addWasmComponentsFromImports(
|
|
3295
|
+
pnpmLockObj.pkgList,
|
|
3296
|
+
allImports,
|
|
3297
|
+
);
|
|
3261
3298
|
if (allImports && Object.keys(allImports).length) {
|
|
3262
3299
|
pkgList = await addEvidenceForImports(
|
|
3263
|
-
|
|
3300
|
+
pkgList,
|
|
3264
3301
|
allImports,
|
|
3265
3302
|
allExports,
|
|
3266
3303
|
options.deep,
|
|
@@ -3335,7 +3372,7 @@ export async function createNodejsBom(path, options) {
|
|
|
3335
3372
|
if (!wpkgJsonFiles?.length) {
|
|
3336
3373
|
if (!workspaceWarningShown) {
|
|
3337
3374
|
workspaceWarningShown = true;
|
|
3338
|
-
console.
|
|
3375
|
+
console.warn(
|
|
3339
3376
|
`Unable to find any package.json files belonging to the workspace '${awp}' referred in ${packageJsonFile}. To improve SBOM precision, run cdxgen from the directory containing the complete source code.`,
|
|
3340
3377
|
);
|
|
3341
3378
|
}
|
|
@@ -3389,7 +3426,7 @@ export async function createNodejsBom(path, options) {
|
|
|
3389
3426
|
// Determine the parent component
|
|
3390
3427
|
const packageJsonF = join(basePath, "package.json");
|
|
3391
3428
|
if (safeExistsSync(packageJsonF)) {
|
|
3392
|
-
const pcs = await parsePkgJson(packageJsonF, true);
|
|
3429
|
+
const pcs = await parsePkgJson(packageJsonF, true, true);
|
|
3393
3430
|
if (pcs.length && Object.keys(pcs[0]).length) {
|
|
3394
3431
|
const tmpParentComponent = { ...pcs[0] };
|
|
3395
3432
|
tmpParentComponent.type = "application";
|
|
@@ -3498,7 +3535,7 @@ export async function createNodejsBom(path, options) {
|
|
|
3498
3535
|
}
|
|
3499
3536
|
if (!parentComponent || !Object.keys(parentComponent).length) {
|
|
3500
3537
|
if (safeExistsSync(join(path, "package.json"))) {
|
|
3501
|
-
const pcs = await parsePkgJson(join(path, "package.json"), true);
|
|
3538
|
+
const pcs = await parsePkgJson(join(path, "package.json"), true, true);
|
|
3502
3539
|
if (pcs.length && Object.keys(pcs[0]).length) {
|
|
3503
3540
|
parentComponent = { ...pcs[0] };
|
|
3504
3541
|
parentComponent.type = "application";
|
|
@@ -3537,6 +3574,7 @@ export async function createNodejsBom(path, options) {
|
|
|
3537
3574
|
options.parentComponent = parentComponent;
|
|
3538
3575
|
}
|
|
3539
3576
|
if (allImports && Object.keys(allImports).length) {
|
|
3577
|
+
pkgList = addWasmComponentsFromImports(pkgList, allImports);
|
|
3540
3578
|
pkgList = await addEvidenceForImports(
|
|
3541
3579
|
pkgList,
|
|
3542
3580
|
allImports,
|
|
@@ -3552,6 +3590,84 @@ export async function createNodejsBom(path, options) {
|
|
|
3552
3590
|
});
|
|
3553
3591
|
}
|
|
3554
3592
|
|
|
3593
|
+
const WASM_IMPORT_PATTERN = /\.wasm([?#].*)?$/i;
|
|
3594
|
+
|
|
3595
|
+
/**
|
|
3596
|
+
* Adds generic wasm components from discovered source imports.
|
|
3597
|
+
*
|
|
3598
|
+
* @param {Array<Object>} pkgList Node.js package list
|
|
3599
|
+
* @param {Object} allImports analyzer imports map
|
|
3600
|
+
* @returns {Array<Object>} pkgList enriched with wasm components
|
|
3601
|
+
*/
|
|
3602
|
+
const addWasmComponentsFromImports = (pkgList, allImports) => {
|
|
3603
|
+
if (!allImports || !Object.keys(allImports).length) {
|
|
3604
|
+
return pkgList;
|
|
3605
|
+
}
|
|
3606
|
+
const existingPurls = new Set();
|
|
3607
|
+
for (const pkg of pkgList) {
|
|
3608
|
+
if (pkg?.purl) {
|
|
3609
|
+
existingPurls.add(pkg.purl);
|
|
3610
|
+
}
|
|
3611
|
+
}
|
|
3612
|
+
for (const [importPath, occurrences] of Object.entries(allImports)) {
|
|
3613
|
+
if (!WASM_IMPORT_PATTERN.test(importPath)) {
|
|
3614
|
+
continue;
|
|
3615
|
+
}
|
|
3616
|
+
const cleanImportPath = importPath.replace(/[?#].*$/, "");
|
|
3617
|
+
const normalizedImportPath = cleanImportPath
|
|
3618
|
+
.replace(/\\/g, "/")
|
|
3619
|
+
.replace(/^\.\//, "");
|
|
3620
|
+
const wasmComponentName = normalizedImportPath || cleanImportPath;
|
|
3621
|
+
const wasmFileName = basename(cleanImportPath);
|
|
3622
|
+
if (!allImports[wasmComponentName]) {
|
|
3623
|
+
allImports[wasmComponentName] = new Set();
|
|
3624
|
+
}
|
|
3625
|
+
for (const occurrence of occurrences) {
|
|
3626
|
+
allImports[wasmComponentName].add(occurrence);
|
|
3627
|
+
}
|
|
3628
|
+
const wasmPurl = new PackageURL(
|
|
3629
|
+
"generic",
|
|
3630
|
+
"",
|
|
3631
|
+
wasmFileName,
|
|
3632
|
+
"",
|
|
3633
|
+
normalizedImportPath ? { path: normalizedImportPath } : undefined,
|
|
3634
|
+
undefined,
|
|
3635
|
+
).toString();
|
|
3636
|
+
if (existingPurls.has(wasmPurl)) {
|
|
3637
|
+
continue;
|
|
3638
|
+
}
|
|
3639
|
+
const firstOccurrence = Array.from(occurrences)[0];
|
|
3640
|
+
const srcFile = firstOccurrence?.importedAs || importPath;
|
|
3641
|
+
pkgList.push({
|
|
3642
|
+
name: wasmComponentName,
|
|
3643
|
+
type: "library",
|
|
3644
|
+
purl: wasmPurl,
|
|
3645
|
+
"bom-ref": wasmPurl,
|
|
3646
|
+
properties: [
|
|
3647
|
+
{
|
|
3648
|
+
name: "SrcFile",
|
|
3649
|
+
value: srcFile,
|
|
3650
|
+
},
|
|
3651
|
+
],
|
|
3652
|
+
evidence: {
|
|
3653
|
+
identity: {
|
|
3654
|
+
field: "purl",
|
|
3655
|
+
confidence: 0.3,
|
|
3656
|
+
methods: [
|
|
3657
|
+
{
|
|
3658
|
+
technique: "filename",
|
|
3659
|
+
confidence: 0.3,
|
|
3660
|
+
value: srcFile,
|
|
3661
|
+
},
|
|
3662
|
+
],
|
|
3663
|
+
},
|
|
3664
|
+
},
|
|
3665
|
+
});
|
|
3666
|
+
existingPurls.add(wasmPurl);
|
|
3667
|
+
}
|
|
3668
|
+
return pkgList;
|
|
3669
|
+
};
|
|
3670
|
+
|
|
3555
3671
|
/**
|
|
3556
3672
|
* Function to create bom string for Projects that use Pixi package manager.
|
|
3557
3673
|
* createPixiBom is based on createPythonBom.
|
|
@@ -3687,6 +3803,14 @@ export async function createPythonBom(path, options) {
|
|
|
3687
3803
|
if (uvLockFiles?.length) {
|
|
3688
3804
|
poetryFiles = poetryFiles.concat(uvLockFiles);
|
|
3689
3805
|
}
|
|
3806
|
+
const pyLockFiles = getAllFiles(
|
|
3807
|
+
path,
|
|
3808
|
+
`${options.multiProject ? "**/" : ""}pylock*.toml`,
|
|
3809
|
+
options,
|
|
3810
|
+
)?.filter((f) => isPyLockFile(f));
|
|
3811
|
+
if (pyLockFiles?.length) {
|
|
3812
|
+
poetryFiles = poetryFiles.concat(pyLockFiles);
|
|
3813
|
+
}
|
|
3690
3814
|
let reqFiles = getAllFiles(
|
|
3691
3815
|
path,
|
|
3692
3816
|
`${options.multiProject ? "**/" : ""}*requirements*.txt`,
|
|
@@ -3752,7 +3876,9 @@ export async function createPythonBom(path, options) {
|
|
|
3752
3876
|
}
|
|
3753
3877
|
// When we identify uv lock files, do not parse requirements files
|
|
3754
3878
|
const requirementsMode =
|
|
3755
|
-
(reqFiles?.length || reqDirFiles?.length) &&
|
|
3879
|
+
(reqFiles?.length || reqDirFiles?.length) &&
|
|
3880
|
+
!uvLockFiles.length &&
|
|
3881
|
+
!pyLockFiles?.length;
|
|
3756
3882
|
const poetryMode = poetryFiles?.length;
|
|
3757
3883
|
|
|
3758
3884
|
// TODO: Support for nested directories
|
|
@@ -3771,6 +3897,12 @@ export async function createPythonBom(path, options) {
|
|
|
3771
3897
|
if (retMap?.workspaceWarningShown) {
|
|
3772
3898
|
options.failOnError && process.exit(1);
|
|
3773
3899
|
}
|
|
3900
|
+
if (retMap?.pyLockProperties?.length) {
|
|
3901
|
+
parentComponent.properties = parentComponent.properties || [];
|
|
3902
|
+
parentComponent.properties = parentComponent.properties.concat(
|
|
3903
|
+
retMap.pyLockProperties,
|
|
3904
|
+
);
|
|
3905
|
+
}
|
|
3774
3906
|
if (retMap.pkgList?.length) {
|
|
3775
3907
|
pkgList = pkgList.concat(retMap.pkgList);
|
|
3776
3908
|
pkgList = trimComponents(pkgList);
|
|
@@ -3790,7 +3922,11 @@ export async function createPythonBom(path, options) {
|
|
|
3790
3922
|
parentComponent,
|
|
3791
3923
|
);
|
|
3792
3924
|
}
|
|
3793
|
-
if (
|
|
3925
|
+
if (
|
|
3926
|
+
(options.deep || !dependencies.length) &&
|
|
3927
|
+
!f.endsWith("uv.lock") &&
|
|
3928
|
+
!isPyLockFile(f)
|
|
3929
|
+
) {
|
|
3794
3930
|
if (options.installDeps) {
|
|
3795
3931
|
retMap = await getPipFrozenTree(
|
|
3796
3932
|
basePath,
|
|
@@ -5583,15 +5719,27 @@ export async function createCocoaBom(path, options) {
|
|
|
5583
5719
|
for (const podFile of cocoaFiles) {
|
|
5584
5720
|
const projectPath = dirname(podFile);
|
|
5585
5721
|
const lockFile = `${podFile}.lock`;
|
|
5586
|
-
|
|
5722
|
+
let missingLockWarningShown = false;
|
|
5723
|
+
if (!safeExistsSync(lockFile)) {
|
|
5587
5724
|
if (options.installDeps) {
|
|
5588
5725
|
executePodCommand(["install"], projectPath, options);
|
|
5589
5726
|
} else {
|
|
5590
5727
|
console.log(
|
|
5591
5728
|
"No 'Podfile.lock' found and '--no-install-deps' is set -- A Podfile.lock is needed to parse dependencies!",
|
|
5592
5729
|
);
|
|
5730
|
+
missingLockWarningShown = true;
|
|
5593
5731
|
options.failOnError && process.exit(1);
|
|
5594
5732
|
}
|
|
5733
|
+
} else if (options.deep && options.installDeps) {
|
|
5734
|
+
executePodCommand(["install"], projectPath, options);
|
|
5735
|
+
}
|
|
5736
|
+
if (!safeExistsSync(lockFile)) {
|
|
5737
|
+
if (!missingLockWarningShown) {
|
|
5738
|
+
console.log(
|
|
5739
|
+
`No 'Podfile.lock' found for ${projectPath}. Skipping CocoaPods dependency parsing for this project.`,
|
|
5740
|
+
);
|
|
5741
|
+
}
|
|
5742
|
+
continue;
|
|
5595
5743
|
}
|
|
5596
5744
|
const parentComponent = await buildObjectForCocoaPod(
|
|
5597
5745
|
{
|
|
@@ -7179,6 +7327,61 @@ export async function createVscodeExtensionBom(path, options) {
|
|
|
7179
7327
|
});
|
|
7180
7328
|
}
|
|
7181
7329
|
|
|
7330
|
+
/**
|
|
7331
|
+
* Function to create BOM for installed Chrome and Chromium-based browser extensions.
|
|
7332
|
+
*
|
|
7333
|
+
* @param {string} path to the project path or a directly provided extension path
|
|
7334
|
+
* @param {Object} options Parse options from the cli
|
|
7335
|
+
* @returns {Promise<Object>} Promise resolving to BOM object
|
|
7336
|
+
*/
|
|
7337
|
+
export async function createChromeExtensionBom(path, options) {
|
|
7338
|
+
let dependencies = [];
|
|
7339
|
+
let sourcePaths = [];
|
|
7340
|
+
const directResult = collectChromeExtensionsFromPath(path);
|
|
7341
|
+
const chromeDirs = discoverChromiumExtensionDirs();
|
|
7342
|
+
let pkgList = directResult.components || [];
|
|
7343
|
+
if (directResult.extensionDirs?.length) {
|
|
7344
|
+
sourcePaths = directResult.extensionDirs.slice();
|
|
7345
|
+
for (const extDir of directResult.extensionDirs) {
|
|
7346
|
+
const deepResult = await analyzeExtensionDir(extDir, options);
|
|
7347
|
+
if (deepResult.pkgList.length) {
|
|
7348
|
+
pkgList = pkgList.concat(deepResult.pkgList);
|
|
7349
|
+
}
|
|
7350
|
+
if (deepResult.dependencies.length) {
|
|
7351
|
+
dependencies = mergeDependencies(dependencies, deepResult.dependencies);
|
|
7352
|
+
}
|
|
7353
|
+
}
|
|
7354
|
+
}
|
|
7355
|
+
if (pkgList.length && DEBUG_MODE) {
|
|
7356
|
+
thoughtLog(
|
|
7357
|
+
`Found ${pkgList.length} component(s) from direct Chrome extension path scan`,
|
|
7358
|
+
);
|
|
7359
|
+
}
|
|
7360
|
+
if (chromeDirs.length) {
|
|
7361
|
+
if (DEBUG_MODE) {
|
|
7362
|
+
thoughtLog(
|
|
7363
|
+
`Discovered Chromium extension directories: ${chromeDirs.map((d) => `${d.browser} (${d.channel}): ${d.dir}`).join(", ")}`,
|
|
7364
|
+
);
|
|
7365
|
+
}
|
|
7366
|
+
if (!pkgList.length) {
|
|
7367
|
+
pkgList = collectInstalledChromeExtensions(chromeDirs);
|
|
7368
|
+
sourcePaths = chromeDirs.map((d) => d.dir);
|
|
7369
|
+
}
|
|
7370
|
+
if (DEBUG_MODE && pkgList.length && !directResult.components?.length) {
|
|
7371
|
+
thoughtLog(
|
|
7372
|
+
`Found ${pkgList.length} Chrome/Chromium extension(s) from ${chromeDirs.length} browser location(s)`,
|
|
7373
|
+
);
|
|
7374
|
+
}
|
|
7375
|
+
}
|
|
7376
|
+
pkgList = trimComponents(pkgList);
|
|
7377
|
+
return buildBomNSData(options, pkgList, CHROME_EXTENSION_PURL_TYPE, {
|
|
7378
|
+
src: path,
|
|
7379
|
+
filename: sourcePaths.join(", "),
|
|
7380
|
+
nsMapping: {},
|
|
7381
|
+
dependencies,
|
|
7382
|
+
});
|
|
7383
|
+
}
|
|
7384
|
+
|
|
7182
7385
|
/**
|
|
7183
7386
|
* Analyze an extracted extension directory for bundled dependencies.
|
|
7184
7387
|
* Looks for npm lock files, node_modules, package.json files, minified JS,
|
|
@@ -7350,7 +7553,7 @@ export function dedupeBom(options, components, parentComponent, dependencies) {
|
|
|
7350
7553
|
components,
|
|
7351
7554
|
bomJson: {
|
|
7352
7555
|
bomFormat: "CycloneDX",
|
|
7353
|
-
specVersion: `${options.specVersion || 1.
|
|
7556
|
+
specVersion: `${options.specVersion || 1.7}`,
|
|
7354
7557
|
serialNumber: serialNum,
|
|
7355
7558
|
version: 1,
|
|
7356
7559
|
metadata: addMetadata(parentComponent, options, {}),
|
|
@@ -8099,6 +8302,46 @@ export async function createMultiXBom(pathList, options) {
|
|
|
8099
8302
|
}
|
|
8100
8303
|
}
|
|
8101
8304
|
}
|
|
8305
|
+
if (hasAnyProjectType(["chrome-extension"], options)) {
|
|
8306
|
+
let isExplicitChromeExtensionPath = false;
|
|
8307
|
+
if (safeExistsSync(path)) {
|
|
8308
|
+
if (basename(path) === "manifest.json") {
|
|
8309
|
+
isExplicitChromeExtensionPath = true;
|
|
8310
|
+
} else {
|
|
8311
|
+
try {
|
|
8312
|
+
isExplicitChromeExtensionPath =
|
|
8313
|
+
statSync(path).isDirectory() &&
|
|
8314
|
+
safeExistsSync(join(path, "manifest.json"));
|
|
8315
|
+
} catch (_err) {
|
|
8316
|
+
isExplicitChromeExtensionPath = false;
|
|
8317
|
+
}
|
|
8318
|
+
}
|
|
8319
|
+
}
|
|
8320
|
+
if (isExplicitChromeExtensionPath || !options.__didScanChromeExtensions) {
|
|
8321
|
+
if (!isExplicitChromeExtensionPath) {
|
|
8322
|
+
options.__didScanChromeExtensions = true;
|
|
8323
|
+
}
|
|
8324
|
+
bomData = await createChromeExtensionBom(path, options);
|
|
8325
|
+
if (bomData?.bomJson?.components?.length) {
|
|
8326
|
+
if (DEBUG_MODE) {
|
|
8327
|
+
console.log(
|
|
8328
|
+
`Found ${bomData.bomJson.components.length} Chrome extension(s) on this host`,
|
|
8329
|
+
);
|
|
8330
|
+
}
|
|
8331
|
+
components = components.concat(bomData.bomJson.components);
|
|
8332
|
+
dependencies = mergeDependencies(
|
|
8333
|
+
dependencies,
|
|
8334
|
+
bomData.bomJson.dependencies,
|
|
8335
|
+
);
|
|
8336
|
+
if (
|
|
8337
|
+
bomData.parentComponent &&
|
|
8338
|
+
Object.keys(bomData.parentComponent).length
|
|
8339
|
+
) {
|
|
8340
|
+
parentSubComponents.push(bomData.parentComponent);
|
|
8341
|
+
}
|
|
8342
|
+
}
|
|
8343
|
+
}
|
|
8344
|
+
}
|
|
8102
8345
|
// Collect any crypto keys
|
|
8103
8346
|
if (options.specVersion >= 1.6 && options.includeCrypto) {
|
|
8104
8347
|
if (!hasAnyProjectType(["oci"], options, false)) {
|
|
@@ -8253,10 +8496,16 @@ export async function createXBom(path, options) {
|
|
|
8253
8496
|
// python
|
|
8254
8497
|
const pipenvMode = safeExistsSync(join(path, "Pipfile"));
|
|
8255
8498
|
const poetryMode = safeExistsSync(join(path, "poetry.lock"));
|
|
8499
|
+
const pyLockFiles = getAllFiles(
|
|
8500
|
+
path,
|
|
8501
|
+
`${options.multiProject ? "**/" : ""}pylock*.toml`,
|
|
8502
|
+
options,
|
|
8503
|
+
).filter((f) => isPyLockFile(f));
|
|
8504
|
+
const pyLockMode = pyLockFiles.length > 0;
|
|
8256
8505
|
const pyProjectMode =
|
|
8257
|
-
!poetryMode && safeExistsSync(join(path, "pyproject.toml"));
|
|
8506
|
+
!poetryMode && !pyLockMode && safeExistsSync(join(path, "pyproject.toml"));
|
|
8258
8507
|
const setupPyMode = safeExistsSync(join(path, "setup.py"));
|
|
8259
|
-
if (pipenvMode || poetryMode || pyProjectMode || setupPyMode) {
|
|
8508
|
+
if (pipenvMode || poetryMode || pyLockMode || pyProjectMode || setupPyMode) {
|
|
8260
8509
|
return await createPythonBom(path, options);
|
|
8261
8510
|
}
|
|
8262
8511
|
const reqFiles = getAllFiles(
|
|
@@ -8818,6 +9067,9 @@ export async function createBom(path, options) {
|
|
|
8818
9067
|
if (PROJECT_TYPE_ALIASES["vscode-extension"].includes(projectType[0])) {
|
|
8819
9068
|
return await createVscodeExtensionBom(path, options);
|
|
8820
9069
|
}
|
|
9070
|
+
if (PROJECT_TYPE_ALIASES["chrome-extension"].includes(projectType[0])) {
|
|
9071
|
+
return await createChromeExtensionBom(path, options);
|
|
9072
|
+
}
|
|
8821
9073
|
switch (projectType[0]) {
|
|
8822
9074
|
case "jar":
|
|
8823
9075
|
return createJarBom(path, options);
|
|
@@ -8856,66 +9108,22 @@ export async function createBom(path, options) {
|
|
|
8856
9108
|
* @throws {Error} if the request fails
|
|
8857
9109
|
*/
|
|
8858
9110
|
export async function submitBom(args, bomContents) {
|
|
8859
|
-
const serverUrl =
|
|
8860
|
-
|
|
8861
|
-
|
|
8862
|
-
);
|
|
8863
|
-
if (encodedBomContents.startsWith("77u/")) {
|
|
8864
|
-
encodedBomContents = encodedBomContents.substring(4);
|
|
8865
|
-
}
|
|
8866
|
-
const bomPayload = {
|
|
8867
|
-
autoCreate: "true",
|
|
8868
|
-
bom: encodedBomContents,
|
|
8869
|
-
};
|
|
8870
|
-
const projectVersion = args.projectVersion || "main";
|
|
8871
|
-
if (
|
|
8872
|
-
typeof args.projectId !== "undefined" ||
|
|
8873
|
-
(typeof args.projectName !== "undefined" &&
|
|
8874
|
-
typeof projectVersion !== "undefined")
|
|
8875
|
-
) {
|
|
8876
|
-
if (typeof args.projectId !== "undefined") {
|
|
8877
|
-
bomPayload.project = args.projectId;
|
|
8878
|
-
}
|
|
8879
|
-
if (typeof args.projectName !== "undefined") {
|
|
8880
|
-
bomPayload.projectName = args.projectName;
|
|
8881
|
-
}
|
|
8882
|
-
if (typeof projectVersion !== "undefined") {
|
|
8883
|
-
bomPayload.projectVersion = projectVersion;
|
|
8884
|
-
}
|
|
8885
|
-
} else {
|
|
9111
|
+
const serverUrl = getDependencyTrackBomUrl(args.serverUrl);
|
|
9112
|
+
const bomPayload = buildDependencyTrackBomPayload(args, bomContents);
|
|
9113
|
+
if (!bomPayload) {
|
|
8886
9114
|
console.log(
|
|
8887
|
-
"projectId
|
|
9115
|
+
"Invalid Dependency-Track submission arguments. Provide projectId or projectName (projectVersion defaults to main) and specify parent project either by UUID or by parent project name + version.",
|
|
8888
9116
|
);
|
|
8889
9117
|
args.failOnError && process.exit(1);
|
|
8890
9118
|
return;
|
|
8891
9119
|
}
|
|
8892
|
-
if (
|
|
8893
|
-
typeof args.parentProjectId !== "undefined" ||
|
|
8894
|
-
typeof args.parentUUID !== "undefined"
|
|
8895
|
-
) {
|
|
8896
|
-
bomPayload.parentUUID = args.parentProjectId || args.parentUUID;
|
|
8897
|
-
}
|
|
8898
|
-
// Add project tags if provided
|
|
8899
|
-
// see https://docs.dependencytrack.org/2024/10/01/v4.12.0/
|
|
8900
|
-
// corresponding API usage documentation can be found on the
|
|
8901
|
-
// API docs site of your instance, see
|
|
8902
|
-
// https://docs.dependencytrack.org/integrations/rest-api/
|
|
8903
|
-
// or public instance see https://yoursky.blue/documentation/rest-api
|
|
8904
|
-
if (typeof args.projectTag !== "undefined") {
|
|
8905
|
-
// If args.projectTag is not an array, convert it to an array
|
|
8906
|
-
// Attention, array items should be of form { name: "tagName " }
|
|
8907
|
-
// see https://yoursky.blue/documentation/rest-api#tag/bom/operation/UploadBomBase64Encoded
|
|
8908
|
-
bomPayload.projectTags = (
|
|
8909
|
-
Array.isArray(args.projectTag) ? args.projectTag : [args.projectTag]
|
|
8910
|
-
).map((tag) => ({ name: tag }));
|
|
8911
|
-
}
|
|
8912
9120
|
if (DEBUG_MODE) {
|
|
8913
9121
|
console.log(
|
|
8914
9122
|
"Submitting BOM to",
|
|
8915
9123
|
serverUrl,
|
|
8916
9124
|
"params",
|
|
8917
9125
|
args.projectName,
|
|
8918
|
-
projectVersion,
|
|
9126
|
+
bomPayload.projectVersion,
|
|
8919
9127
|
);
|
|
8920
9128
|
}
|
|
8921
9129
|
try {
|