diff --git a/README.md b/README.md index 0b5d3e34a0..2333711b15 100644 --- a/README.md +++ b/README.md @@ -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] diff --git a/bin/cdxgen.js b/bin/cdxgen.js index e29d02d1f4..7f8ff4338f 100755 --- a/bin/cdxgen.js +++ b/bin/cdxgen.js @@ -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", diff --git a/docs/CLI.md b/docs/CLI.md index 07d0c47a3e..47421e40ec 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -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] diff --git a/docs/README.md b/docs/README.md index 3632f08e18..1ad2a922ec 100644 --- a/docs/README.md +++ b/docs/README.md @@ -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 diff --git a/lib/cli/index.js b/lib/cli/index.js index c1465b5409..81d1637e56 100644 --- a/lib/cli/index.js +++ b/lib/cli/index.js @@ -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", diff --git a/lib/cli/index.poku.js b/lib/cli/index.poku.js new file mode 100644 index 0000000000..fd3ac42b0e --- /dev/null +++ b/lib/cli/index.poku.js @@ -0,0 +1,133 @@ +import { afterEach, assert, beforeEach, describe, it } from "poku"; +import quibble from "quibble"; +import sinon from "sinon"; + +describe("CLI tests", () => { + describe("submitBom()", () => { + 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?update=${Date.now()}`)); + }); + + afterEach(async () => { + await quibble.reset(); + sinon.reset(); + }); + + 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); + }); + + it("should successfully report the SBOM with given parent project, name, version and multiple single tags", async () => { + const serverUrl = "https://dtrack.example.com"; + const projectName = "cdxgen-test-project"; + const projectVersion = "1.0.0"; + const projectTag = "tag1"; + const parentProjectId = "f7cb9f02-8041-4991-9101-b01fa07a6522"; + const bomContent = { + bom: "test", + }; + const apiKey = "TEST_API_KEY"; + const skipDtTlsCheck = false; + + const expectedRequestPayload = { + autoCreate: "true", + bom: "eyJib20iOiJ0ZXN0In0=", // stringified and base64 encoded bomContent + parentUUID: parentProjectId, + projectName, + projectVersion, + projectTags: [{ name: projectTag }], + }; + + await submitBom( + { + serverUrl, + parentProjectId, + 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); + }); + }); +}); diff --git a/lib/helpers/utils.poku.js b/lib/helpers/utils.poku.js index 14e77e557f..b7bda7106a 100644 --- a/lib/helpers/utils.poku.js +++ b/lib/helpers/utils.poku.js @@ -3942,8 +3942,8 @@ it("parsePnpmLock", async () => { 3, ); parsedList = await parsePnpmLock("./pnpm-lock.yaml"); - assert.deepStrictEqual(parsedList.pkgList.length, 355); - assert.deepStrictEqual(parsedList.dependenciesList.length, 355); + assert.deepStrictEqual(parsedList.pkgList.length, 367); + assert.deepStrictEqual(parsedList.dependenciesList.length, 367); assert.ok(parsedList.pkgList[0]); assert.ok(parsedList.dependenciesList[0]); parsedList = await parsePnpmLock( diff --git a/lib/server/server.js b/lib/server/server.js index 0e54cf895d..a13f468cbf 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -34,6 +34,7 @@ const ALLOWED_PARAMS = [ "projectId", "projectName", "projectGroup", + "projectTag", "projectVersion", "parentUUID", "serverUrl", diff --git a/package.json b/package.json index 5a16dc7cb7..7008706d69 100644 --- a/package.json +++ b/package.json @@ -139,6 +139,9 @@ "@npmcli/package-json": "7.0.1", "@npmcli/query": "4.0.1", "@npmcli/redact": "3.2.2", + "@sinonjs/commons": "3.0.1", + "@sinonjs/fake-timers": "13.0.5", + "@sinonjs/samsam": "8.0.3", "abbrev": "4.0.0", "ajv": "8.17.1", "ajv-formats": "3.0.1", @@ -191,11 +194,13 @@ "promise-all-reject-late": "1.0.1", "promise-call-limit": "3.0.2", "properties-reader": "2.3.0", + "quibble": "0.9.2", "read-package-json-fast": "4.0.0", "responselike": "4.0.2", "semver": "7.7.3", "sequelize": "6.37.7", "signal-exit": "4.1.0", + "sinon": "21.0.0", "sprintf-js": "1.1.3", "sqlite3": "npm:@appthreat/sqlite3@6.0.9", "ssri": "12.0.0", @@ -273,6 +278,8 @@ "devDependencies": { "@biomejs/biome": "2.2.6", "poku": "3.0.2", + "quibble": "0.9.2", + "sinon": "21.0.0", "typescript": "5.9.3" }, "optionalDependencies": { @@ -335,6 +342,9 @@ "@npmcli/package-json": "7.0.1", "@npmcli/query": "4.0.1", "@npmcli/redact": "3.2.2", + "@sinonjs/commons": "3.0.1", + "@sinonjs/fake-timers": "13.0.5", + "@sinonjs/samsam": "8.0.3", "abbrev": "4.0.0", "ajv": "8.17.1", "ajv-formats": "3.0.1", @@ -387,11 +397,13 @@ "promise-all-reject-late": "1.0.1", "promise-call-limit": "3.0.2", "properties-reader": "2.3.0", + "quibble": "0.9.2", "read-package-json-fast": "4.0.0", "responselike": "4.0.2", "semver": "7.7.3", "sequelize": "6.37.7", "signal-exit": "4.1.0", + "sinon": "21.0.0", "sprintf-js": "1.1.3", "sqlite3": "npm:@appthreat/sqlite3@6.0.9", "ssri": "12.0.0", @@ -437,5 +449,9 @@ "onFail": "ignore" } ] + }, + "volta": { + "node": "22.21.0", + "pnpm": "10.19.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 49b809e223..0e599a5754 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ overrides: '@npmcli/package-json': 7.0.1 '@npmcli/query': 4.0.1 '@npmcli/redact': 3.2.2 + '@sinonjs/commons': 3.0.1 + '@sinonjs/fake-timers': 13.0.5 + '@sinonjs/samsam': 8.0.3 abbrev: 4.0.0 ajv: 8.17.1 ajv-formats: 3.0.1 @@ -84,11 +87,13 @@ overrides: promise-all-reject-late: 1.0.1 promise-call-limit: 3.0.2 properties-reader: 2.3.0 + quibble: 0.9.2 read-package-json-fast: 4.0.0 responselike: 4.0.2 semver: 7.7.3 sequelize: 6.37.7 signal-exit: 4.1.0 + sinon: 21.0.0 sprintf-js: 1.1.3 sqlite3: npm:@appthreat/sqlite3@6.0.9 ssri: 12.0.0 @@ -275,6 +280,12 @@ importers: poku: specifier: 3.0.2 version: 3.0.2 + quibble: + specifier: 0.9.2 + version: 0.9.2 + sinon: + specifier: 21.0.0 + version: 21.0.0 typescript: specifier: 5.9.3 version: 5.9.3 @@ -351,16 +362,16 @@ packages: hasBin: true '@appthreat/atom@2.4.2': - resolution: {integrity: sha512-z9PkDrSydnuP+VoBeHcF4evVE98S1+ZASWfMR0ryBFUEDsZCWw3/bs8bpZNqwBYSo5/58ilEJRUcHQs7HwtbTA==} + resolution: {integrity: sha512-z9PkDrSydnuP+VoBeHcF4evVE98S1+ZASWfMR0ryBFUEDsZCWw3/bs8bpZNqwBYSo5/58ilEJRUcHQs7HwtbTA==, tarball: https://registry.npmjs.org/@appthreat/atom/-/atom-2.4.2.tgz} engines: {node: '>=16.0.0'} hasBin: true '@appthreat/cdx-proto@1.1.4': - resolution: {integrity: sha512-cAC1EpAesqMOfaOl1Q37WN38PV+nbc3MQmab0p3cVGsrL3KWP3dUbNWRdzN4sVL/gVOYEouwvR/PXvDF9WCeVA==} + resolution: {integrity: sha512-cAC1EpAesqMOfaOl1Q37WN38PV+nbc3MQmab0p3cVGsrL3KWP3dUbNWRdzN4sVL/gVOYEouwvR/PXvDF9WCeVA==, tarball: https://registry.npmjs.org/@appthreat/cdx-proto/-/cdx-proto-1.1.4.tgz} engines: {node: '>=20'} '@appthreat/sqlite3@6.0.9': - resolution: {integrity: sha512-Aim5tAIusHm2zZVhqedZwl1MGiSMaWhJ9Ev9ctBuv82fJv/gmE0FhHY/tv/ikoMTNGWlaClAgJayfPLJxvkQ7Q==} + resolution: {integrity: sha512-Aim5tAIusHm2zZVhqedZwl1MGiSMaWhJ9Ev9ctBuv82fJv/gmE0FhHY/tv/ikoMTNGWlaClAgJayfPLJxvkQ7Q==, tarball: https://registry.npmjs.org/@appthreat/sqlite3/-/sqlite3-6.0.9.tgz} engines: {node: '>=20'} '@babel/code-frame@7.27.1': @@ -406,53 +417,53 @@ packages: hasBin: true '@biomejs/cli-darwin-arm64@2.2.6': - resolution: {integrity: sha512-UZPmn3M45CjTYulgcrFJFZv7YmK3pTxTJDrFYlNElT2FNnkkX4fsxjExTSMeWKQYoZjvekpH5cvrYZZlWu3yfA==} + resolution: {integrity: sha512-UZPmn3M45CjTYulgcrFJFZv7YmK3pTxTJDrFYlNElT2FNnkkX4fsxjExTSMeWKQYoZjvekpH5cvrYZZlWu3yfA==, tarball: https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.6.tgz} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] '@biomejs/cli-darwin-x64@2.2.6': - resolution: {integrity: sha512-HOUIquhHVgh/jvxyClpwlpl/oeMqntlteL89YqjuFDiZ091P0vhHccwz+8muu3nTyHWM5FQslt+4Jdcd67+xWQ==} + resolution: {integrity: sha512-HOUIquhHVgh/jvxyClpwlpl/oeMqntlteL89YqjuFDiZ091P0vhHccwz+8muu3nTyHWM5FQslt+4Jdcd67+xWQ==, tarball: https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.6.tgz} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] '@biomejs/cli-linux-arm64-musl@2.2.6': - resolution: {integrity: sha512-TjCenQq3N6g1C+5UT3jE1bIiJb5MWQvulpUngTIpFsL4StVAUXucWD0SL9MCW89Tm6awWfeXBbZBAhJwjyFbRQ==} + resolution: {integrity: sha512-TjCenQq3N6g1C+5UT3jE1bIiJb5MWQvulpUngTIpFsL4StVAUXucWD0SL9MCW89Tm6awWfeXBbZBAhJwjyFbRQ==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.6.tgz} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] libc: [musl] '@biomejs/cli-linux-arm64@2.2.6': - resolution: {integrity: sha512-BpGtuMJGN+o8pQjvYsUKZ+4JEErxdSmcRD/JG3mXoWc6zrcA7OkuyGFN1mDggO0Q1n7qXxo/PcupHk8gzijt5g==} + resolution: {integrity: sha512-BpGtuMJGN+o8pQjvYsUKZ+4JEErxdSmcRD/JG3mXoWc6zrcA7OkuyGFN1mDggO0Q1n7qXxo/PcupHk8gzijt5g==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.6.tgz} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] libc: [glibc] '@biomejs/cli-linux-x64-musl@2.2.6': - resolution: {integrity: sha512-1ZcBux8zVM3JhWN2ZCPaYf0+ogxXG316uaoXJdgoPZcdK/rmRcRY7PqHdAos2ExzvjIdvhQp72UcveI98hgOog==} + resolution: {integrity: sha512-1ZcBux8zVM3JhWN2ZCPaYf0+ogxXG316uaoXJdgoPZcdK/rmRcRY7PqHdAos2ExzvjIdvhQp72UcveI98hgOog==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.6.tgz} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] libc: [musl] '@biomejs/cli-linux-x64@2.2.6': - resolution: {integrity: sha512-1HaM/dpI/1Z68zp8ZdT6EiBq+/O/z97a2AiHMl+VAdv5/ELckFt9EvRb8hDHpk8hUMoz03gXkC7VPXOVtU7faA==} + resolution: {integrity: sha512-1HaM/dpI/1Z68zp8ZdT6EiBq+/O/z97a2AiHMl+VAdv5/ELckFt9EvRb8hDHpk8hUMoz03gXkC7VPXOVtU7faA==, tarball: https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.6.tgz} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] libc: [glibc] '@biomejs/cli-win32-arm64@2.2.6': - resolution: {integrity: sha512-h3A88G8PGM1ryTeZyLlSdfC/gz3e95EJw9BZmA6Po412DRqwqPBa2Y9U+4ZSGUAXCsnSQE00jLV8Pyrh0d+jQw==} + resolution: {integrity: sha512-h3A88G8PGM1ryTeZyLlSdfC/gz3e95EJw9BZmA6Po412DRqwqPBa2Y9U+4ZSGUAXCsnSQE00jLV8Pyrh0d+jQw==, tarball: https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.6.tgz} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] '@biomejs/cli-win32-x64@2.2.6': - resolution: {integrity: sha512-yx0CqeOhPjYQ5ZXgPfu8QYkgBhVJyvWe36as7jRuPrKPO5ylVDfwVtPQ+K/mooNTADW0IhxOZm3aPu16dP8yNQ==} + resolution: {integrity: sha512-yx0CqeOhPjYQ5ZXgPfu8QYkgBhVJyvWe36as7jRuPrKPO5ylVDfwVtPQ+K/mooNTADW0IhxOZm3aPu16dP8yNQ==, tarball: https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.6.tgz} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -461,63 +472,63 @@ packages: resolution: {integrity: sha512-fdRs9PSrBF7QUntpZpq6BTw58fhgGJojgg39m9oFOJGZT+nip9b0so5cYY1oWl5pvemDLr0cPPsH46vwThEbpQ==} '@cyclonedx/cdxgen-plugins-bin-darwin-amd64@1.7.0': - resolution: {integrity: sha512-evJAEetfhKU7N9tCaOl/CZcs4upoEIKvLdhV9ogzk9QIur+HtZX5F9LddGNoQuzhB1Umy2tAyFAKhl+EX63BFQ==} + resolution: {integrity: sha512-evJAEetfhKU7N9tCaOl/CZcs4upoEIKvLdhV9ogzk9QIur+HtZX5F9LddGNoQuzhB1Umy2tAyFAKhl+EX63BFQ==, tarball: https://registry.npmjs.org/@cyclonedx/cdxgen-plugins-bin-darwin-amd64/-/cdxgen-plugins-bin-darwin-amd64-1.7.0.tgz} cpu: [x64] os: [darwin] '@cyclonedx/cdxgen-plugins-bin-darwin-arm64@1.7.0': - resolution: {integrity: sha512-gnQqfDNd8RXKH3n/BUtSi1aJghPLSVpAScaM0iiuGvdfOVuwqBEMAKx/SC0v5yXdCtThC45W5/Zz8Lc9eNoNAw==} + resolution: {integrity: sha512-gnQqfDNd8RXKH3n/BUtSi1aJghPLSVpAScaM0iiuGvdfOVuwqBEMAKx/SC0v5yXdCtThC45W5/Zz8Lc9eNoNAw==, tarball: https://registry.npmjs.org/@cyclonedx/cdxgen-plugins-bin-darwin-arm64/-/cdxgen-plugins-bin-darwin-arm64-1.7.0.tgz} cpu: [arm64] os: [darwin] '@cyclonedx/cdxgen-plugins-bin-linux-amd64@1.7.0': - resolution: {integrity: sha512-Nitd3y1yb8Xv2e7ODqki3M8DO6SzWe/gGsioRiA6iNXcQ/JYzg03CyHEaTjCAhJXFO4qraCn4N6OPN2H7c8bew==} + resolution: {integrity: sha512-Nitd3y1yb8Xv2e7ODqki3M8DO6SzWe/gGsioRiA6iNXcQ/JYzg03CyHEaTjCAhJXFO4qraCn4N6OPN2H7c8bew==, tarball: https://registry.npmjs.org/@cyclonedx/cdxgen-plugins-bin-linux-amd64/-/cdxgen-plugins-bin-linux-amd64-1.7.0.tgz} cpu: [x64] os: [linux] libc: glibc '@cyclonedx/cdxgen-plugins-bin-linux-arm64@1.7.0': - resolution: {integrity: sha512-/96YdFdwASQVr+MDO1IbUMYbLoHawTDIsGlhyMV4AI47qKZ59Ein5dvdibqqmnxgmWvG4Vqp941gRaCBlCLWag==} + resolution: {integrity: sha512-/96YdFdwASQVr+MDO1IbUMYbLoHawTDIsGlhyMV4AI47qKZ59Ein5dvdibqqmnxgmWvG4Vqp941gRaCBlCLWag==, tarball: https://registry.npmjs.org/@cyclonedx/cdxgen-plugins-bin-linux-arm64/-/cdxgen-plugins-bin-linux-arm64-1.7.0.tgz} cpu: [arm64] os: [linux] libc: glibc '@cyclonedx/cdxgen-plugins-bin-linux-arm@1.7.0': - resolution: {integrity: sha512-eNnS9Kd+j4YDiIotCA3EQWyiHKjx7iZqh5+gyF38zmSJQRssEWvCdv+IPvXPyZw8hh5g9/8IQWPYMFpB3fpopg==} + resolution: {integrity: sha512-eNnS9Kd+j4YDiIotCA3EQWyiHKjx7iZqh5+gyF38zmSJQRssEWvCdv+IPvXPyZw8hh5g9/8IQWPYMFpB3fpopg==, tarball: https://registry.npmjs.org/@cyclonedx/cdxgen-plugins-bin-linux-arm/-/cdxgen-plugins-bin-linux-arm-1.7.0.tgz} cpu: [arm] os: [linux] libc: glibc '@cyclonedx/cdxgen-plugins-bin-linux-ppc64@1.7.0': - resolution: {integrity: sha512-AWLQ33x/mUtYLfIfCq8tZ8TykXUzzNo6ZLvf1eOmEeEyYw/9Yx6E7KzzaAakGl886lJW/1gzmhvFPXD+ZKEIpA==} + resolution: {integrity: sha512-AWLQ33x/mUtYLfIfCq8tZ8TykXUzzNo6ZLvf1eOmEeEyYw/9Yx6E7KzzaAakGl886lJW/1gzmhvFPXD+ZKEIpA==, tarball: https://registry.npmjs.org/@cyclonedx/cdxgen-plugins-bin-linux-ppc64/-/cdxgen-plugins-bin-linux-ppc64-1.7.0.tgz} cpu: [ppc64] os: [linux] libc: glibc '@cyclonedx/cdxgen-plugins-bin-linuxmusl-amd64@1.7.0': - resolution: {integrity: sha512-miYABkiNS+0m0z9L5lfIyiAQezuYthkzzPqX6DgPeMgFT8SfoUng2dtRzkCPLtCUBj8lMyBntXTjZrmH7QOMoA==} + resolution: {integrity: sha512-miYABkiNS+0m0z9L5lfIyiAQezuYthkzzPqX6DgPeMgFT8SfoUng2dtRzkCPLtCUBj8lMyBntXTjZrmH7QOMoA==, tarball: https://registry.npmjs.org/@cyclonedx/cdxgen-plugins-bin-linuxmusl-amd64/-/cdxgen-plugins-bin-linuxmusl-amd64-1.7.0.tgz} cpu: [x64] os: [linux] libc: musl '@cyclonedx/cdxgen-plugins-bin-linuxmusl-arm64@1.7.0': - resolution: {integrity: sha512-Rh8ChTldyY/01EWrciyhnUltC2YNLmdkwaPDZsJT/as1Bu0Q4iOnepMw2WpqwzkaGbZG5PgFtzeuV1kBKjo07Q==} + resolution: {integrity: sha512-Rh8ChTldyY/01EWrciyhnUltC2YNLmdkwaPDZsJT/as1Bu0Q4iOnepMw2WpqwzkaGbZG5PgFtzeuV1kBKjo07Q==, tarball: https://registry.npmjs.org/@cyclonedx/cdxgen-plugins-bin-linuxmusl-arm64/-/cdxgen-plugins-bin-linuxmusl-arm64-1.7.0.tgz} cpu: [arm64] os: [linux] libc: musl '@cyclonedx/cdxgen-plugins-bin-windows-amd64@1.7.0': - resolution: {integrity: sha512-sCeTnlDq3Wojit2+MqErsYhD/Mv7VickLU2PazmamQc4LVZHakZPGxoG4CFUt4oFVux9CoY1+RxkE+Ia+E+fsA==} + resolution: {integrity: sha512-sCeTnlDq3Wojit2+MqErsYhD/Mv7VickLU2PazmamQc4LVZHakZPGxoG4CFUt4oFVux9CoY1+RxkE+Ia+E+fsA==, tarball: https://registry.npmjs.org/@cyclonedx/cdxgen-plugins-bin-windows-amd64/-/cdxgen-plugins-bin-windows-amd64-1.7.0.tgz} cpu: [x64] os: [win32] '@cyclonedx/cdxgen-plugins-bin-windows-arm64@1.7.0': - resolution: {integrity: sha512-AzQrY0H1A7JduJTBr/Ub7ppt9RKXjc2+AXV38dvekXYvKSnwnR4715gEZ0mwRnn/BZ4az0uQwMlJCpY8qttJIg==} + resolution: {integrity: sha512-AzQrY0H1A7JduJTBr/Ub7ppt9RKXjc2+AXV38dvekXYvKSnwnR4715gEZ0mwRnn/BZ4az0uQwMlJCpY8qttJIg==, tarball: https://registry.npmjs.org/@cyclonedx/cdxgen-plugins-bin-windows-arm64/-/cdxgen-plugins-bin-windows-arm64-1.7.0.tgz} cpu: [arm64] os: [win32] '@cyclonedx/cdxgen-plugins-bin@1.7.0': - resolution: {integrity: sha512-pgPMY2vHKMTcW24qtcql0uIck3t66U+QmUrO7C6E8kg06tJqBgo8PtT58FhI4B41lPrpq8rAQzo2jLCLu1JnCw==} + resolution: {integrity: sha512-pgPMY2vHKMTcW24qtcql0uIck3t66U+QmUrO7C6E8kg06tJqBgo8PtT58FhI4B41lPrpq8rAQzo2jLCLu1JnCw==, tarball: https://registry.npmjs.org/@cyclonedx/cdxgen-plugins-bin/-/cdxgen-plugins-bin-1.7.0.tgz} cpu: [x64] '@iarna/toml@2.2.5': @@ -606,6 +617,15 @@ packages: resolution: {integrity: sha512-7F/yz2IphV39hiS2zB4QYVkivrptHHh0K8qJJd9HhuWSdvf8AN7NpebW3CcDZDBQsUPMoDKWsY2WWgW7bqOcfA==} engines: {node: '>=18'} + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@13.0.5': + resolution: {integrity: sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==} + + '@sinonjs/samsam@8.0.3': + resolution: {integrity: sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==} + '@szmarczak/http-timer@5.0.1': resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} engines: {node: '>=14.16'} @@ -672,7 +692,7 @@ packages: resolution: {integrity: sha512-b3N5eTW1g7vXkw+0CXh/HazGTcO5KYuu/RCNaJbDMPI6LHDi+7qe8EmxKUVe1sUbY2KZOVZFyj62x0OEz9qyAA==} bare-fs@4.4.4: - resolution: {integrity: sha512-Q8yxM1eLhJfuM7KXVP3zjhBvtMJCYRByoTT+wHXjpdMELv0xICFJX+1w4c7csa+WZEOsq4ItJ4RGwvzid6m/dw==} + resolution: {integrity: sha512-Q8yxM1eLhJfuM7KXVP3zjhBvtMJCYRByoTT+wHXjpdMELv0xICFJX+1w4c7csa+WZEOsq4ItJ4RGwvzid6m/dw==, tarball: https://registry.npmjs.org/bare-fs/-/bare-fs-4.4.4.tgz} engines: {bare: '>=1.16.0'} peerDependencies: bare-buffer: '*' @@ -685,7 +705,7 @@ packages: engines: {bare: '>=1.14.0'} bare-path@3.0.0: - resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} + resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==, tarball: https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz} bare-stream@2.7.0: resolution: {integrity: sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==} @@ -709,7 +729,7 @@ packages: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} body-parser@2.2.0: - resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==, tarball: https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz} engines: {node: '>=18'} boolbase@1.0.0: @@ -773,11 +793,11 @@ packages: engines: {node: '>= 0.6'} compression@1.8.1: - resolution: {integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==} + resolution: {integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==, tarball: https://registry.npmjs.org/compression/-/compression-1.8.1.tgz} engines: {node: '>= 0.8.0'} connect@3.7.0: - resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} + resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==, tarball: https://registry.npmjs.org/connect/-/connect-3.7.0.tgz} engines: {node: '>= 0.10.0'} content-type@1.0.5: @@ -840,6 +860,10 @@ packages: detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + diff@7.0.0: + resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==} + engines: {node: '>=0.3.1'} + dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} @@ -1083,6 +1107,10 @@ packages: resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} engines: {node: '>= 12'} + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -1121,7 +1149,7 @@ packages: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} jsonata@2.1.0: - resolution: {integrity: sha512-OCzaRMK8HobtX8fp37uIVmL8CY1IGc/a6gLsDqz3quExFR09/U78HUzWYr7T31UEB6+Eu0/8dkVD5fFDOl9a8w==} + resolution: {integrity: sha512-OCzaRMK8HobtX8fp37uIVmL8CY1IGc/a6gLsDqz3quExFR09/U78HUzWYr7T31UEB6+Eu0/8dkVD5fFDOl9a8w==, tarball: https://registry.npmjs.org/jsonata/-/jsonata-2.1.0.tgz} engines: {node: '>= 8'} just-diff-apply@5.5.0: @@ -1257,7 +1285,7 @@ packages: engines: {node: ^18 || ^20 || >= 21} node-gyp@11.5.0: - resolution: {integrity: sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==} + resolution: {integrity: sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==, tarball: https://registry.npmjs.org/node-gyp/-/node-gyp-11.5.0.tgz} engines: {node: ^18.17.0 || >=20.5.0} hasBin: true @@ -1351,6 +1379,9 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@2.0.0: resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} engines: {node: 20 || >=22} @@ -1411,6 +1442,10 @@ packages: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} + quibble@0.9.2: + resolution: {integrity: sha512-BrL7hrZcbyyt5ZDfePkGFDc3m82uUtxCPOnpRUrkOdtBnmV9ldQKxXORkKL8eIzToRNaCpIPyKyfdfq/tBlFAA==} + engines: {node: '>= 0.14.0'} + quick-lru@5.1.1: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} @@ -1442,6 +1477,11 @@ packages: resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + responselike@4.0.2: resolution: {integrity: sha512-cGk8IbWEAnaCpdAt1BHzJ3Ahz5ewDJa0KseTsE3qIRMJ3C698W8psM7byCeWVpd/Ha7FUYzuRVzXoKoM6nRUbA==} engines: {node: '>=20'} @@ -1479,7 +1519,7 @@ packages: engines: {node: '>= 10.0.0'} sequelize@6.37.7: - resolution: {integrity: sha512-mCnh83zuz7kQxxJirtFD7q6Huy6liPanI67BSlbzSYgVNl5eXVdE2CN1FuAeZwG1SNpGsNRCV+bJAVVnykZAFA==} + resolution: {integrity: sha512-mCnh83zuz7kQxxJirtFD7q6Huy6liPanI67BSlbzSYgVNl5eXVdE2CN1FuAeZwG1SNpGsNRCV+bJAVVnykZAFA==, tarball: https://registry.npmjs.org/sequelize/-/sequelize-6.37.7.tgz} engines: {node: '>=10.0.0'} peerDependencies: ibm_db: '*' @@ -1552,6 +1592,9 @@ packages: simple-get@4.0.1: resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + sinon@21.0.0: + resolution: {integrity: sha512-TOgRcwFPbfGtpqvZw+hyqJDvqfapr1qUlOizROIk4bBLjlsjlB00Pg6wMFXNtJRpu+eCZuVOaLatG7M8105kAw==} + slice-ansi@4.0.0: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} engines: {node: '>=10'} @@ -1614,6 +1657,10 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + table@6.9.0: resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} engines: {node: '>=10.0.0'} @@ -1649,6 +1696,14 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==, tarball: https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz} + engines: {node: '>=4'} + + type-detect@4.1.0: + resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} + engines: {node: '>=4'} + type-fest@4.41.0: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} @@ -1728,7 +1783,7 @@ packages: resolution: {integrity: sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==} wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, tarball: https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz} engines: {node: '>=10'} wrappy@1.0.2: @@ -2024,6 +2079,19 @@ snapshots: '@sindresorhus/is@7.1.0': {} + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@13.0.5': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@sinonjs/samsam@8.0.3': + dependencies: + '@sinonjs/commons': 3.0.1 + type-detect: 4.1.0 + '@szmarczak/http-timer@5.0.1': dependencies: defer-to-connect: 2.0.1 @@ -2303,6 +2371,8 @@ snapshots: detect-node@2.1.0: {} + diff@7.0.0: {} + dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -2436,8 +2506,7 @@ snapshots: minipass: 7.1.2 optional: true - function-bind@1.1.2: - optional: true + function-bind@1.1.2: {} get-caller-file@2.0.5: {} @@ -2522,7 +2591,6 @@ snapshots: hasown@2.0.2: dependencies: function-bind: 1.1.2 - optional: true hosted-git-info@9.0.2: dependencies: @@ -2584,6 +2652,10 @@ snapshots: ip-address@10.0.1: optional: true + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + is-fullwidth-code-point@3.0.0: {} is-stream@4.0.1: {} @@ -2630,8 +2702,7 @@ snapshots: lodash.truncate@4.4.2: {} - lodash@4.17.21: - optional: true + lodash@4.17.21: {} lowercase-keys@3.0.0: {} @@ -2856,6 +2927,8 @@ snapshots: path-key@3.1.1: {} + path-parse@1.0.7: {} + path-scurry@2.0.0: dependencies: lru-cache: 11.2.2 @@ -2925,6 +2998,11 @@ snapshots: side-channel: 1.1.0 optional: true + quibble@0.9.2: + dependencies: + lodash: 4.17.21 + resolve: 1.22.10 + quick-lru@5.1.1: {} raw-body@3.0.1: @@ -2956,6 +3034,12 @@ snapshots: resolve-alpn@1.2.1: {} + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + responselike@4.0.2: dependencies: lowercase-keys: 3.0.0 @@ -3068,6 +3152,13 @@ snapshots: simple-concat: 1.0.1 optional: true + sinon@21.0.0: + dependencies: + '@sinonjs/commons': 3.0.1 + '@sinonjs/fake-timers': 13.0.5 + '@sinonjs/samsam': 8.0.3 + diff: 7.0.0 + slice-ansi@4.0.0: dependencies: ansi-styles: 4.3.0 @@ -3148,6 +3239,8 @@ snapshots: strip-json-comments@3.1.1: optional: true + supports-preserve-symlinks-flag@1.0.0: {} + table@6.9.0: dependencies: ajv: 8.17.1 @@ -3211,6 +3304,10 @@ snapshots: safe-buffer: 5.2.1 optional: true + type-detect@4.0.8: {} + + type-detect@4.1.0: {} + type-fest@4.41.0: {} type-is@2.0.1: