Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ Options:
--project-group Dependency track project group
--project-name Dependency track project name. Default use the directory name
--project-version Dependency track project version [string] [default: ""]
--project-tag Dependency track project tag. Multiple values allowed. [array]
--project-id Dependency track project id. Either provide the id or the project name and version tog
ether [string]
--parent-project-id Dependency track parent project id [string]
Expand Down
3 changes: 3 additions & 0 deletions bin/cdxgen.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ const args = _yargs
default: "",
type: "string",
})
.option("project-tag", {
description: "Dependency track project tag. Multiple values allowed.",
})
.option("project-id", {
description:
"Dependency track project id. Either provide the id or the project name and version together",
Expand Down
1 change: 1 addition & 0 deletions docs/CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ Options:
--project-group Dependency track project group
--project-name Dependency track project name. Default use the directory name
--project-version Dependency track project version [string] [default: ""]
--project-tag Dependency track project tags. Multiple values allowed. [array]
--project-id Dependency track project id. Either provide the id or the project name and version tog
ether [string]
--parent-project-id Dependency track parent project id [string]
Expand Down
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ Invoke cdxgen with the below arguments to automatically submit the BOM to your o
--project-name Dependency track project name. Default use the di
rectory name
--project-version Dependency track project version [default: ""]
--project-tag Dependency track project tag. Multiple values all
owed. [array]
--project-id Dependency track project id. Either provide the i
d or the project name and version together
--parent-project-id Dependency track parent project id
Expand Down
14 changes: 14 additions & 0 deletions lib/cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8688,6 +8688,20 @@ export async function submitBom(args, bomContents) {
) {
bomPayload.parentUUID = args.parentProjectId || args.parentUUID;
}
// Add project tags if provided
// see https://docs.dependencytrack.org/2024/10/01/v4.12.0/
// corresponding API usage documentation can be found on the
// API docs site of your instance, see
// https://docs.dependencytrack.org/integrations/rest-api/
// or public instance see https://yoursky.blue/documentation/rest-api
if (typeof args.projectTag !== "undefined") {
// If args.projectTag is not an array, convert it to an array
// Attention, array items should be of form { name: "tagName " }
// see https://yoursky.blue/documentation/rest-api#tag/bom/operation/UploadBomBase64Encoded
bomPayload.projectTags = (
Array.isArray(args.projectTag) ? args.projectTag : [args.projectTag]
).map((tag) => ({ name: tag }));
}
if (DEBUG_MODE) {
console.log(
"Submitting BOM to",
Expand Down
73 changes: 73 additions & 0 deletions lib/cli/index.poku.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import quibble from "quibble";
import sinon from "sinon";
import { assert, beforeEach, afterEach, describe, it } from "poku";

describe("CLI tests", () => {
let gotStub;
let submitBom;

beforeEach(async () => {
// Create a sinon stub that mimics got()
const fakeGotResponse = {
json: sinon.stub().resolves({ success: true }),
};

gotStub = sinon.stub().returns(fakeGotResponse);

// Attach extend to the function itself
gotStub.extend = sinon.stub().returns(gotStub);

// Replace the real 'got' module with our stub
await quibble.esm("got", {
default: gotStub,
});

// Import the module under test AFTER quibble
({ submitBom } = await import("./index.js"));
});

afterEach(() => {
quibble.reset(); // Restore real modules
});

it("should successfully report the SBOM with given project id, name, version and a single tag", async () => {
const serverUrl = "https://dtrack.example.com";
const projectId = "f7cb9f02-8041-4991-9101-b01fa07a6522";
const projectName = "cdxgen-test-project";
const projectVersion = "1.0.0";
const projectTag = "tag1";
const bomContent = {
bom: "test"
};
const apiKey = "TEST_API_KEY";
const skipDtTlsCheck = false;

const expectedRequestPayload = {
autoCreate: "true",
bom: "eyJib20iOiJ0ZXN0In0=", // stringified and base64 encoded bomContent
project: projectId,
projectName,
projectVersion,
projectTags: [{ name: projectTag }],
};

await submitBom(
{ serverUrl, projectId, projectName, projectVersion, apiKey, skipDtTlsCheck, projectTag },
bomContent,
);

// Verify got was called exactly once
sinon.assert.calledOnce(gotStub);

// Grab call arguments
const [calledUrl, options] = gotStub.firstCall.args;

// Assert call arguments against expectations
assert.equal(calledUrl, serverUrl + "/api/v1/bom");
assert.equal(options.method, "PUT");
assert.equal(options.https.rejectUnauthorized, !skipDtTlsCheck);
assert.equal(options.headers["X-Api-Key"], apiKey);
assert.match(options.headers["user-agent"], /@CycloneDX\/cdxgen/);
assert.deepEqual(options.json, expectedRequestPayload);
});
});
1 change: 1 addition & 0 deletions lib/server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const ALLOWED_PARAMS = [
"projectId",
"projectName",
"projectGroup",
"projectTag",
"projectVersion",
"parentUUID",
"serverUrl",
Expand Down
134 changes: 132 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,17 @@
"@npmcli/package-json": "7.0.1",
"@npmcli/query": "4.0.1",
"@npmcli/redact": "3.2.2",
"@sec-ant/readable-stream": "0.4.1",
"@sindresorhus/is": "7.1.0",
"@sinonjs/commons": "3.0.1",
"@sinonjs/fake-timers": "13.0.5",
"@sinonjs/samsam": "8.0.3",
"@szmarczak/http-timer": "5.0.1",
"@types/debug": "4.1.12",
"@types/http-cache-semantics": "4.0.4",
"@types/ms": "2.1.0",
"@types/node": "24.5.1",
"@types/validator": "13.15.3",
"abbrev": "3.0.1",
"ajv": "8.17.1",
"ajv-formats": "3.0.1",
Expand All @@ -151,7 +162,22 @@
"compression": "1.8.1",
"connect": "3.7.0",
"debug": "4.4.1",
"decompress-response": "7.0.0",
"decompress-response": "6.0.0",
"deep-extend": "0.6.0",
"defer-to-connect": "2.0.1",
"define-data-property": "1.1.4",
"define-properties": "1.2.1",
"depd": "2.0.0",
"detect-libc": "2.1.0",
"detect-node": "2.1.0",
"diff": "7.0.0",
"dom-serializer": "2.0.0",
"domelementtype": "2.3.0",
"domhandler": "5.0.3",
"domutils": "3.2.2",
"dottie": "2.0.6",
"dunder-proto": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"edn-data": "1.1.2",
"encoding": "0.1.13",
"escape-string-regexp": "4.0.0",
Expand All @@ -161,6 +187,9 @@
"hosted-git-info": "9.0.2",
"iconv-lite": "0.7.0",
"ini": "5.0.0",
"ip-address": "10.0.1",
"is-core-module": "2.16.1",
"is-fullwidth-code-point": "3.0.0",
"is-stream": "4.0.1",
"isexe": "3.1.1",
"json-parse-even-better-errors": "4.0.0",
Expand All @@ -184,26 +213,61 @@
"on-finished": "2.4.1",
"packageurl-js": "1.0.2",
"parse-conflict-json": "4.0.0",
"parse5": "7.3.0",
"parse5-htmlparser2-tree-adapter": "7.1.0",
"parse5-parser-stream": "7.1.2",
"parseurl": "1.3.3",
"path-key": "3.1.1",
"path-parse": "1.0.7",
"path-scurry": "2.0.0",
"pg-connection-string": "2.9.1",
"picocolors": "1.1.1",
"picomatch": "4.0.3",
"poku": "3.0.2",
"prettify-xml": "1.2.0",
"proc-log": "5.0.0",
"proggy": "3.0.0",
"promise-all-reject-late": "1.0.1",
"promise-call-limit": "3.0.2",
"properties-reader": "2.3.0",
"pump": "3.0.3",
"qs": "6.14.0",
"quibble": "0.9.2",
"quick-lru": "5.1.1",
"raw-body": "3.0.1",
"rc": "1.2.8",
"read-cmd-shim": "5.0.0",
"read-package-json-fast": "4.0.0",
"require-directory": "2.1.1",
"require-from-string": "2.0.2",
"resolve-alpn": "1.2.1",
"resolve": "1.22.10",
"responselike": "4.0.2",
"semver": "7.7.3",
"sequelize": "6.37.7",
"signal-exit": "4.1.0",
"simple-concat": "1.0.1",
"simple-get": "4.0.1",
"sinon": "21.0.0",
"slice-ansi": "4.0.0",
"smart-buffer": "4.2.0",
"socks": "2.8.7",
"socks-proxy-agent": "8.0.5",
"spdx-correct": "3.2.0",
"spdx-exceptions": "2.5.0",
"spdx-expression-parse": "3.0.1",
"spdx-license-ids": "3.0.22",
"sprintf-js": "1.1.3",
"sqlite3": "npm:@appthreat/[email protected]",
"ssri": "12.0.0",
"statuses": "2.0.2",
"strip-json-comments": "3.1.1",
"supports-preserve-symlinks-flag": "1.0.0",
"table": "6.9.0",
"tar": "7.5.1",
"treeverse": "3.0.0",
"tunnel-agent": "0.6.0",
"type-detect": "4.1.0",
"type-fest": "4.41.0",
"typescript": "5.9.3",
"unique-filename": "4.0.0",
Expand Down Expand Up @@ -273,6 +337,8 @@
"devDependencies": {
"@biomejs/biome": "2.2.6",
"poku": "3.0.2",
"quibble": "0.9.2",
"sinon": "21.0.0",
"typescript": "5.9.3"
},
"optionalDependencies": {
Expand Down Expand Up @@ -335,6 +401,17 @@
"@npmcli/package-json": "7.0.1",
"@npmcli/query": "4.0.1",
"@npmcli/redact": "3.2.2",
"@sec-ant/readable-stream": "0.4.1",
"@sindresorhus/is": "7.1.0",
"@sinonjs/commons": "3.0.1",
"@sinonjs/fake-timers": "13.0.5",
"@sinonjs/samsam": "8.0.3",
"@szmarczak/http-timer": "5.0.1",
"@types/debug": "4.1.12",
"@types/http-cache-semantics": "4.0.4",
"@types/ms": "2.1.0",
"@types/node": "24.5.1",
"@types/validator": "13.15.3",
"abbrev": "3.0.1",
"ajv": "8.17.1",
"ajv-formats": "3.0.1",
Expand All @@ -347,7 +424,22 @@
"compression": "1.8.1",
"connect": "3.7.0",
"debug": "4.4.1",
"decompress-response": "7.0.0",
"decompress-response": "6.0.0",
"deep-extend": "0.6.0",
"defer-to-connect": "2.0.1",
"define-data-property": "1.1.4",
"define-properties": "1.2.1",
"depd": "2.0.0",
"detect-libc": "2.1.0",
"detect-node": "2.1.0",
"diff": "7.0.0",
"dom-serializer": "2.0.0",
"domelementtype": "2.3.0",
"domhandler": "5.0.3",
"domutils": "3.2.2",
"dottie": "2.0.6",
"dunder-proto": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"edn-data": "1.1.2",
"encoding": "0.1.13",
"escape-string-regexp": "4.0.0",
Expand All @@ -357,6 +449,9 @@
"hosted-git-info": "9.0.2",
"iconv-lite": "0.7.0",
"ini": "5.0.0",
"ip-address": "10.0.1",
"is-core-module": "2.16.1",
"is-fullwidth-code-point": "3.0.0",
"is-stream": "4.0.1",
"isexe": "3.1.1",
"json-parse-even-better-errors": "4.0.0",
Expand All @@ -380,27 +475,62 @@
"on-finished": "2.4.1",
"packageurl-js": "1.0.2",
"parse-conflict-json": "4.0.0",
"parse5": "7.3.0",
"parse5-htmlparser2-tree-adapter": "7.1.0",
"parse5-parser-stream": "7.1.2",
"parseurl": "1.3.3",
"path-key": "3.1.1",
"path-parse": "1.0.7",
"path-scurry": "2.0.0",
"pg-connection-string": "2.9.1",
"picocolors": "1.1.1",
"picomatch": "4.0.3",
"poku": "3.0.2",
"prettify-xml": "1.2.0",
"proc-log": "5.0.0",
"proggy": "3.0.0",
"promise-all-reject-late": "1.0.1",
"promise-call-limit": "3.0.2",
"properties-reader": "2.3.0",
"pump": "3.0.3",
"qs": "6.14.0",
"quibble": "0.9.2",
"quick-lru": "5.1.1",
"raw-body": "3.0.1",
"rc": "1.2.8",
"read-cmd-shim": "5.0.0",
"read-package-json-fast": "4.0.0",
"require-directory": "2.1.1",
"require-from-string": "2.0.2",
"resolve-alpn": "1.2.1",
"resolve": "1.22.10",
"responselike": "4.0.2",
"semver": "7.7.3",
"sequelize": "6.37.7",
"signal-exit": "4.1.0",
"simple-concat": "1.0.1",
"simple-get": "4.0.1",
"sinon": "21.0.0",
"slice-ansi": "4.0.0",
"smart-buffer": "4.2.0",
"socks": "2.8.7",
"socks-proxy-agent": "8.0.5",
"spdx-correct": "3.2.0",
"spdx-exceptions": "2.5.0",
"spdx-expression-parse": "3.0.1",
"spdx-license-ids": "3.0.22",
"sprintf-js": "1.1.3",
"sqlite3": "npm:@appthreat/[email protected]",
"ssri": "12.0.0",
"statuses": "2.0.2",
"strip-json-comments": "3.1.1",
"supports-preserve-symlinks-flag": "1.0.0",
"table": "6.9.0",
"tar": "7.5.1",
"tar-fs": "3.1.1",
"treeverse": "3.0.0",
"tunnel-agent": "0.6.0",
"type-detect": "4.1.0",
"type-fest": "4.41.0",
"typescript": "5.9.3",
"unique-filename": "4.0.0",
Expand Down
Loading
Loading