@cyclonedx/cdxgen 12.2.0 → 12.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/bin/cdxgen.js +19 -1
- package/lib/cli/index.js +122 -57
- package/lib/cli/index.poku.js +117 -0
- package/lib/helpers/analyzer.js +606 -3
- package/lib/helpers/analyzer.poku.js +230 -0
- package/lib/helpers/depsUtils.js +16 -0
- package/lib/helpers/depsUtils.poku.js +58 -1
- package/lib/helpers/display.js +4 -2
- package/lib/helpers/remote/dependency-track.js +84 -0
- package/lib/helpers/remote/dependency-track.poku.js +119 -0
- package/lib/helpers/table.js +384 -0
- package/lib/helpers/table.poku.js +186 -0
- package/lib/helpers/utils.js +184 -10
- package/lib/helpers/utils.poku.js +118 -11
- package/lib/server/openapi.yaml +33 -0
- package/lib/server/server.js +10 -2
- package/lib/server/server.poku.js +209 -0
- package/lib/stages/postgen/auditBom.js +1 -2
- package/lib/validator/reporters/console.js +2 -2
- package/package.json +1 -2
- package/types/lib/cli/index.d.ts.map +1 -1
- package/types/lib/helpers/analyzer.d.ts.map +1 -1
- package/types/lib/helpers/depsUtils.d.ts.map +1 -1
- package/types/lib/helpers/display.d.ts.map +1 -1
- 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/table.d.ts +6 -0
- package/types/lib/helpers/table.d.ts.map +1 -0
- package/types/lib/helpers/utils.d.ts +1 -0
- package/types/lib/helpers/utils.d.ts.map +1 -1
- package/types/lib/server/server.d.ts +1 -0
- package/types/lib/server/server.d.ts.map +1 -1
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -107,7 +107,7 @@ docker run --rm -e CDXGEN_DEBUG_MODE=debug -v /tmp:/tmp -v $(pwd):/app:rw -t ghc
|
|
|
107
107
|
In deno applications, cdxgen could be directly imported without any conversion. Please see the section on [integration as a library](#integration-as-library)
|
|
108
108
|
|
|
109
109
|
```ts
|
|
110
|
-
import { createBom, submitBom } from "npm:@cyclonedx/cdxgen@^12.2.
|
|
110
|
+
import { createBom, submitBom } from "npm:@cyclonedx/cdxgen@^12.2.1";
|
|
111
111
|
```
|
|
112
112
|
|
|
113
113
|
## Getting Help
|
|
@@ -139,7 +139,10 @@ Options:
|
|
|
139
139
|
--project-tag Dependency track project tag. Multiple values allowed. [array]
|
|
140
140
|
--project-id Dependency track project id. Either provide the id or the project name and version tog
|
|
141
141
|
ether [string]
|
|
142
|
-
--parent-project-id Dependency track parent project id
|
|
142
|
+
--parent-project-id Dependency track parent project id. You must provide the id or both
|
|
143
|
+
parent project name and parent project version. [string]
|
|
144
|
+
--parent-project-name Dependency track parent project name [string]
|
|
145
|
+
--parent-project-version Dependency track parent project version [string]
|
|
143
146
|
--required-only Include only the packages with required scope on the SBOM. Would set compositions.aggr
|
|
144
147
|
egate to incomplete unless --no-auto-compositions is passed. [boolean]
|
|
145
148
|
--fail-on-error Fail if any dependency extractor fails. [boolean]
|
package/bin/cdxgen.js
CHANGED
|
@@ -171,6 +171,24 @@ const args = _yargs
|
|
|
171
171
|
description: "Dependency track parent project id",
|
|
172
172
|
type: "string",
|
|
173
173
|
})
|
|
174
|
+
.option("parent-project-name", {
|
|
175
|
+
description: "Dependency track parent project name",
|
|
176
|
+
type: "string",
|
|
177
|
+
})
|
|
178
|
+
.option("parent-project-version", {
|
|
179
|
+
description: "Dependency track parent project version",
|
|
180
|
+
type: "string",
|
|
181
|
+
})
|
|
182
|
+
.option("auto-create", {
|
|
183
|
+
description: "Dependency track autoCreate value for BOM uploads",
|
|
184
|
+
type: "boolean",
|
|
185
|
+
hidden: true,
|
|
186
|
+
})
|
|
187
|
+
.option("is-latest", {
|
|
188
|
+
description: "Dependency track isLatest value for BOM uploads",
|
|
189
|
+
type: "boolean",
|
|
190
|
+
hidden: true,
|
|
191
|
+
})
|
|
174
192
|
.option("required-only", {
|
|
175
193
|
type: "boolean",
|
|
176
194
|
description:
|
|
@@ -249,7 +267,7 @@ const args = _yargs
|
|
|
249
267
|
hidden: true,
|
|
250
268
|
})
|
|
251
269
|
.option("spec-version", {
|
|
252
|
-
description: "CycloneDX Specification version to use. Defaults to 1.
|
|
270
|
+
description: "CycloneDX Specification version to use. Defaults to 1.7",
|
|
253
271
|
default: 1.7,
|
|
254
272
|
type: "number",
|
|
255
273
|
choices: [1.4, 1.5, 1.6, 1.7],
|
package/lib/cli/index.js
CHANGED
|
@@ -19,7 +19,6 @@ 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
|
|
|
@@ -28,6 +27,11 @@ import { parseCaxaMetadata } from "../helpers/caxa.js";
|
|
|
28
27
|
import { mergeDependencies, trimComponents } from "../helpers/depsUtils.js";
|
|
29
28
|
import { GIT_COMMAND } from "../helpers/envcontext.js";
|
|
30
29
|
import { thoughtLog } from "../helpers/logger.js";
|
|
30
|
+
import {
|
|
31
|
+
buildDependencyTrackBomPayload,
|
|
32
|
+
getDependencyTrackBomUrl,
|
|
33
|
+
} from "../helpers/remote/dependency-track.js";
|
|
34
|
+
import { table } from "../helpers/table.js";
|
|
31
35
|
import {
|
|
32
36
|
addEvidenceForDotnet,
|
|
33
37
|
addEvidenceForImports,
|
|
@@ -1252,7 +1256,7 @@ const buildBomNSData = (options, pkgInfo, ptype, context) => {
|
|
|
1252
1256
|
// CycloneDX Json Template
|
|
1253
1257
|
const jsonTpl = {
|
|
1254
1258
|
bomFormat: "CycloneDX",
|
|
1255
|
-
specVersion: `${options.specVersion || "1.
|
|
1259
|
+
specVersion: `${options.specVersion || "1.7"}`,
|
|
1256
1260
|
serialNumber: serialNum,
|
|
1257
1261
|
version: 1,
|
|
1258
1262
|
metadata: metadata,
|
|
@@ -1490,6 +1494,8 @@ export async function createJavaBom(path, options) {
|
|
|
1490
1494
|
}
|
|
1491
1495
|
let result;
|
|
1492
1496
|
let mvnArgs;
|
|
1497
|
+
// FIXME: How do we motivate everyone to upgrade to 1.7?
|
|
1498
|
+
const toolsSpecVersion = 1.6;
|
|
1493
1499
|
if (isQuarkus) {
|
|
1494
1500
|
thoughtLog(
|
|
1495
1501
|
"This appears to be a Quarkus project. Let's use the right Maven plugin.",
|
|
@@ -1500,12 +1506,14 @@ export async function createJavaBom(path, options) {
|
|
|
1500
1506
|
"quarkus:dependency-sbom",
|
|
1501
1507
|
"-Dquarkus.analytics.disabled=true",
|
|
1502
1508
|
];
|
|
1503
|
-
if (options.specVersion) {
|
|
1509
|
+
if (options.specVersion >= 1.6) {
|
|
1504
1510
|
mvnArgs = mvnArgs.concat(
|
|
1505
|
-
`-Dquarkus.dependency.sbom.schema-version=${
|
|
1511
|
+
`-Dquarkus.dependency.sbom.schema-version=${toolsSpecVersion}`,
|
|
1506
1512
|
);
|
|
1507
1513
|
}
|
|
1508
1514
|
} else {
|
|
1515
|
+
// FIXME: The last maven plugin release was on November 28th, 2024.
|
|
1516
|
+
// Should we fork this repo and maintain it ourselves?
|
|
1509
1517
|
const cdxMavenPlugin =
|
|
1510
1518
|
process.env.CDX_MAVEN_PLUGIN ||
|
|
1511
1519
|
"org.cyclonedx:cyclonedx-maven-plugin:2.9.1";
|
|
@@ -1527,9 +1535,11 @@ export async function createJavaBom(path, options) {
|
|
|
1527
1535
|
const addArgs = process.env.MVN_ARGS.split(" ");
|
|
1528
1536
|
mvnArgs = mvnArgs.concat(addArgs);
|
|
1529
1537
|
}
|
|
1530
|
-
// specVersion 1.4 doesn't support externalReferences.type=
|
|
1538
|
+
// specVersion 1.4 doesn't support externalReferences.type=distribution-intake
|
|
1531
1539
|
// so we need to run the plugin with the correct version
|
|
1532
|
-
if (options.specVersion) {
|
|
1540
|
+
if (options.specVersion >= 1.6) {
|
|
1541
|
+
mvnArgs = mvnArgs.concat(`-DschemaVersion=${toolsSpecVersion}`);
|
|
1542
|
+
} else if (options.specVersion > 1.4) {
|
|
1533
1543
|
mvnArgs = mvnArgs.concat(`-DschemaVersion=${options.specVersion}`);
|
|
1534
1544
|
}
|
|
1535
1545
|
}
|
|
@@ -2723,6 +2733,21 @@ export async function createNodejsBom(path, options) {
|
|
|
2723
2733
|
`${options.multiProject ? "**/" : ""}bower.json`,
|
|
2724
2734
|
options,
|
|
2725
2735
|
);
|
|
2736
|
+
if (DEBUG_MODE) {
|
|
2737
|
+
const wasmFiles = getAllFiles(
|
|
2738
|
+
path,
|
|
2739
|
+
`${options.multiProject ? "**/" : ""}*.wasm`,
|
|
2740
|
+
{
|
|
2741
|
+
...options,
|
|
2742
|
+
includeNodeModulesDir: true,
|
|
2743
|
+
},
|
|
2744
|
+
);
|
|
2745
|
+
if (wasmFiles?.length) {
|
|
2746
|
+
console.log(
|
|
2747
|
+
`Found ${wasmFiles.length} wasm files in this project. cdxgen will make a best attempt to identify the exports and imports from these files.`,
|
|
2748
|
+
);
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2726
2751
|
// Parse min js files
|
|
2727
2752
|
if (minJsFiles?.length) {
|
|
2728
2753
|
manifestFiles = manifestFiles.concat(minJsFiles);
|
|
@@ -3242,6 +3267,7 @@ export async function createNodejsBom(path, options) {
|
|
|
3242
3267
|
const pnpmLock = join(path, "common", "config", "rush", "pnpm-lock.yaml");
|
|
3243
3268
|
if (safeExistsSync(swFile)) {
|
|
3244
3269
|
let pkgList = await parseNodeShrinkwrap(swFile);
|
|
3270
|
+
pkgList = addWasmComponentsFromImports(pkgList, allImports);
|
|
3245
3271
|
if (allImports && Object.keys(allImports).length) {
|
|
3246
3272
|
pkgList = await addEvidenceForImports(
|
|
3247
3273
|
pkgList,
|
|
@@ -3258,9 +3284,13 @@ export async function createNodejsBom(path, options) {
|
|
|
3258
3284
|
}
|
|
3259
3285
|
if (safeExistsSync(pnpmLock)) {
|
|
3260
3286
|
const pnpmLockObj = await parsePnpmLock(pnpmLock);
|
|
3287
|
+
let pkgList = addWasmComponentsFromImports(
|
|
3288
|
+
pnpmLockObj.pkgList,
|
|
3289
|
+
allImports,
|
|
3290
|
+
);
|
|
3261
3291
|
if (allImports && Object.keys(allImports).length) {
|
|
3262
3292
|
pkgList = await addEvidenceForImports(
|
|
3263
|
-
|
|
3293
|
+
pkgList,
|
|
3264
3294
|
allImports,
|
|
3265
3295
|
allExports,
|
|
3266
3296
|
options.deep,
|
|
@@ -3537,6 +3567,7 @@ export async function createNodejsBom(path, options) {
|
|
|
3537
3567
|
options.parentComponent = parentComponent;
|
|
3538
3568
|
}
|
|
3539
3569
|
if (allImports && Object.keys(allImports).length) {
|
|
3570
|
+
pkgList = addWasmComponentsFromImports(pkgList, allImports);
|
|
3540
3571
|
pkgList = await addEvidenceForImports(
|
|
3541
3572
|
pkgList,
|
|
3542
3573
|
allImports,
|
|
@@ -3552,6 +3583,84 @@ export async function createNodejsBom(path, options) {
|
|
|
3552
3583
|
});
|
|
3553
3584
|
}
|
|
3554
3585
|
|
|
3586
|
+
const WASM_IMPORT_PATTERN = /\.wasm([?#].*)?$/i;
|
|
3587
|
+
|
|
3588
|
+
/**
|
|
3589
|
+
* Adds generic wasm components from discovered source imports.
|
|
3590
|
+
*
|
|
3591
|
+
* @param {Array<Object>} pkgList Node.js package list
|
|
3592
|
+
* @param {Object} allImports analyzer imports map
|
|
3593
|
+
* @returns {Array<Object>} pkgList enriched with wasm components
|
|
3594
|
+
*/
|
|
3595
|
+
const addWasmComponentsFromImports = (pkgList, allImports) => {
|
|
3596
|
+
if (!allImports || !Object.keys(allImports).length) {
|
|
3597
|
+
return pkgList;
|
|
3598
|
+
}
|
|
3599
|
+
const existingPurls = new Set();
|
|
3600
|
+
for (const pkg of pkgList) {
|
|
3601
|
+
if (pkg?.purl) {
|
|
3602
|
+
existingPurls.add(pkg.purl);
|
|
3603
|
+
}
|
|
3604
|
+
}
|
|
3605
|
+
for (const [importPath, occurrences] of Object.entries(allImports)) {
|
|
3606
|
+
if (!WASM_IMPORT_PATTERN.test(importPath)) {
|
|
3607
|
+
continue;
|
|
3608
|
+
}
|
|
3609
|
+
const cleanImportPath = importPath.replace(/[?#].*$/, "");
|
|
3610
|
+
const normalizedImportPath = cleanImportPath
|
|
3611
|
+
.replace(/\\/g, "/")
|
|
3612
|
+
.replace(/^\.\//, "");
|
|
3613
|
+
const wasmComponentName = normalizedImportPath || cleanImportPath;
|
|
3614
|
+
const wasmFileName = basename(cleanImportPath);
|
|
3615
|
+
if (!allImports[wasmComponentName]) {
|
|
3616
|
+
allImports[wasmComponentName] = new Set();
|
|
3617
|
+
}
|
|
3618
|
+
for (const occurrence of occurrences) {
|
|
3619
|
+
allImports[wasmComponentName].add(occurrence);
|
|
3620
|
+
}
|
|
3621
|
+
const wasmPurl = new PackageURL(
|
|
3622
|
+
"generic",
|
|
3623
|
+
"",
|
|
3624
|
+
wasmFileName,
|
|
3625
|
+
"",
|
|
3626
|
+
normalizedImportPath ? { path: normalizedImportPath } : undefined,
|
|
3627
|
+
undefined,
|
|
3628
|
+
).toString();
|
|
3629
|
+
if (existingPurls.has(wasmPurl)) {
|
|
3630
|
+
continue;
|
|
3631
|
+
}
|
|
3632
|
+
const firstOccurrence = Array.from(occurrences)[0];
|
|
3633
|
+
const srcFile = firstOccurrence?.importedAs || importPath;
|
|
3634
|
+
pkgList.push({
|
|
3635
|
+
name: wasmComponentName,
|
|
3636
|
+
type: "library",
|
|
3637
|
+
purl: wasmPurl,
|
|
3638
|
+
"bom-ref": wasmPurl,
|
|
3639
|
+
properties: [
|
|
3640
|
+
{
|
|
3641
|
+
name: "SrcFile",
|
|
3642
|
+
value: srcFile,
|
|
3643
|
+
},
|
|
3644
|
+
],
|
|
3645
|
+
evidence: {
|
|
3646
|
+
identity: {
|
|
3647
|
+
field: "purl",
|
|
3648
|
+
confidence: 0.3,
|
|
3649
|
+
methods: [
|
|
3650
|
+
{
|
|
3651
|
+
technique: "filename",
|
|
3652
|
+
confidence: 0.3,
|
|
3653
|
+
value: srcFile,
|
|
3654
|
+
},
|
|
3655
|
+
],
|
|
3656
|
+
},
|
|
3657
|
+
},
|
|
3658
|
+
});
|
|
3659
|
+
existingPurls.add(wasmPurl);
|
|
3660
|
+
}
|
|
3661
|
+
return pkgList;
|
|
3662
|
+
};
|
|
3663
|
+
|
|
3555
3664
|
/**
|
|
3556
3665
|
* Function to create bom string for Projects that use Pixi package manager.
|
|
3557
3666
|
* createPixiBom is based on createPythonBom.
|
|
@@ -7350,7 +7459,7 @@ export function dedupeBom(options, components, parentComponent, dependencies) {
|
|
|
7350
7459
|
components,
|
|
7351
7460
|
bomJson: {
|
|
7352
7461
|
bomFormat: "CycloneDX",
|
|
7353
|
-
specVersion: `${options.specVersion || 1.
|
|
7462
|
+
specVersion: `${options.specVersion || 1.7}`,
|
|
7354
7463
|
serialNumber: serialNum,
|
|
7355
7464
|
version: 1,
|
|
7356
7465
|
metadata: addMetadata(parentComponent, options, {}),
|
|
@@ -8856,66 +8965,22 @@ export async function createBom(path, options) {
|
|
|
8856
8965
|
* @throws {Error} if the request fails
|
|
8857
8966
|
*/
|
|
8858
8967
|
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 {
|
|
8968
|
+
const serverUrl = getDependencyTrackBomUrl(args.serverUrl);
|
|
8969
|
+
const bomPayload = buildDependencyTrackBomPayload(args, bomContents);
|
|
8970
|
+
if (!bomPayload) {
|
|
8886
8971
|
console.log(
|
|
8887
|
-
"projectId
|
|
8972
|
+
"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
8973
|
);
|
|
8889
8974
|
args.failOnError && process.exit(1);
|
|
8890
8975
|
return;
|
|
8891
8976
|
}
|
|
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
8977
|
if (DEBUG_MODE) {
|
|
8913
8978
|
console.log(
|
|
8914
8979
|
"Submitting BOM to",
|
|
8915
8980
|
serverUrl,
|
|
8916
8981
|
"params",
|
|
8917
8982
|
args.projectName,
|
|
8918
|
-
projectVersion,
|
|
8983
|
+
bomPayload.projectVersion,
|
|
8919
8984
|
);
|
|
8920
8985
|
}
|
|
8921
8986
|
try {
|
package/lib/cli/index.poku.js
CHANGED
|
@@ -120,5 +120,122 @@ describe("CLI tests", () => {
|
|
|
120
120
|
assert.match(options.headers["user-agent"], /@CycloneDX\/cdxgen/);
|
|
121
121
|
assert.deepEqual(options.json, expectedRequestPayload);
|
|
122
122
|
});
|
|
123
|
+
|
|
124
|
+
it("should include parentName and parentVersion when parent project name and version are passed", async () => {
|
|
125
|
+
const fakeGotResponse = {
|
|
126
|
+
json: sinon.stub().resolves({ success: true }),
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const gotStub = sinon.stub().returns(fakeGotResponse);
|
|
130
|
+
gotStub.extend = sinon.stub().returns(gotStub);
|
|
131
|
+
|
|
132
|
+
const { submitBom } = await esmock("./index.js", {
|
|
133
|
+
got: { default: gotStub },
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const serverUrl = "https://dtrack.example.com";
|
|
137
|
+
const projectName = "cdxgen-test-project";
|
|
138
|
+
const projectVersion = "2.0.0";
|
|
139
|
+
const parentProjectName = "parent-project";
|
|
140
|
+
const parentProjectVersion = "1.0.0";
|
|
141
|
+
const bomContent = {
|
|
142
|
+
bom: "test3",
|
|
143
|
+
};
|
|
144
|
+
const apiKey = "TEST_API_KEY";
|
|
145
|
+
const skipDtTlsCheck = false;
|
|
146
|
+
|
|
147
|
+
const expectedRequestPayload = {
|
|
148
|
+
autoCreate: "true",
|
|
149
|
+
bom: "eyJib20iOiJ0ZXN0MyJ9", // stringified and base64 encoded bomContent
|
|
150
|
+
parentName: parentProjectName,
|
|
151
|
+
parentVersion: parentProjectVersion,
|
|
152
|
+
projectName,
|
|
153
|
+
projectVersion,
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
await submitBom(
|
|
157
|
+
{
|
|
158
|
+
serverUrl,
|
|
159
|
+
projectName,
|
|
160
|
+
projectVersion,
|
|
161
|
+
parentProjectName,
|
|
162
|
+
parentProjectVersion,
|
|
163
|
+
apiKey,
|
|
164
|
+
skipDtTlsCheck,
|
|
165
|
+
},
|
|
166
|
+
bomContent,
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
sinon.assert.calledOnce(gotStub);
|
|
170
|
+
const [calledUrl, options] = gotStub.firstCall.args;
|
|
171
|
+
|
|
172
|
+
assert.equal(calledUrl, `${serverUrl}/api/v1/bom`);
|
|
173
|
+
assert.equal(options.method, "PUT");
|
|
174
|
+
assert.equal(options.https.rejectUnauthorized, !skipDtTlsCheck);
|
|
175
|
+
assert.equal(options.headers["X-Api-Key"], apiKey);
|
|
176
|
+
assert.match(options.headers["user-agent"], /@CycloneDX\/cdxgen/);
|
|
177
|
+
assert.deepEqual(options.json, expectedRequestPayload);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("should include configurable autoCreate and isLatest values in payload", async () => {
|
|
181
|
+
const fakeGotResponse = {
|
|
182
|
+
json: sinon.stub().resolves({ success: true }),
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const gotStub = sinon.stub().returns(fakeGotResponse);
|
|
186
|
+
gotStub.extend = sinon.stub().returns(gotStub);
|
|
187
|
+
|
|
188
|
+
const { submitBom } = await esmock("./index.js", {
|
|
189
|
+
got: { default: gotStub },
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const serverUrl = "https://dtrack.example.com";
|
|
193
|
+
const projectName = "cdxgen-test-project";
|
|
194
|
+
const apiKey = "TEST_API_KEY";
|
|
195
|
+
|
|
196
|
+
await submitBom(
|
|
197
|
+
{
|
|
198
|
+
serverUrl,
|
|
199
|
+
projectName,
|
|
200
|
+
apiKey,
|
|
201
|
+
autoCreate: false,
|
|
202
|
+
isLatest: true,
|
|
203
|
+
},
|
|
204
|
+
{ bom: "test4" },
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
sinon.assert.calledOnce(gotStub);
|
|
208
|
+
const [_calledUrl, options] = gotStub.firstCall.args;
|
|
209
|
+
assert.equal(options.json.autoCreate, "false");
|
|
210
|
+
assert.equal(options.json.isLatest, true);
|
|
211
|
+
assert.equal(options.json.projectVersion, "main");
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("should reject invalid mixed parent modes before making network request", async () => {
|
|
215
|
+
const fakeGotResponse = {
|
|
216
|
+
json: sinon.stub().resolves({ success: true }),
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const gotStub = sinon.stub().returns(fakeGotResponse);
|
|
220
|
+
gotStub.extend = sinon.stub().returns(gotStub);
|
|
221
|
+
|
|
222
|
+
const { submitBom } = await esmock("./index.js", {
|
|
223
|
+
got: { default: gotStub },
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const response = await submitBom(
|
|
227
|
+
{
|
|
228
|
+
serverUrl: "https://dtrack.example.com",
|
|
229
|
+
projectName: "cdxgen-test-project",
|
|
230
|
+
parentProjectId: "5103b8b4-4ca3-46ea-8051-036a3b2ab17e",
|
|
231
|
+
parentProjectName: "parent",
|
|
232
|
+
parentProjectVersion: "1.0.0",
|
|
233
|
+
},
|
|
234
|
+
{ bom: "test5" },
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
assert.equal(response, undefined);
|
|
238
|
+
sinon.assert.notCalled(gotStub);
|
|
239
|
+
});
|
|
123
240
|
});
|
|
124
241
|
});
|