diff --git a/README.md b/README.md index 1e5fd5e14e..8dc28d55ad 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,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 a4453a3a07..4d64f8652a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -146,6 +146,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 a0e3489fd1..a1eddc48f8 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 4209a20dcc..5893622944 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, 354); - assert.deepStrictEqual(parsedList.dependenciesList.length, 354); + 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 96ea612343..9d55285fc4 100644 --- a/package.json +++ b/package.json @@ -146,6 +146,9 @@ "@npmcli/package-json": "7.0.2", "@npmcli/query": "5.0.0", "@npmcli/redact": "4.0.0", + "@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", @@ -199,11 +202,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": "5.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": "13.0.0", @@ -282,6 +287,8 @@ "devDependencies": { "@biomejs/biome": "2.3.4", "poku": "3.0.2", + "quibble": "0.9.2", + "sinon": "21.0.0", "typescript": "5.9.3" }, "optionalDependencies": { @@ -351,6 +358,9 @@ "@npmcli/package-json": "7.0.2", "@npmcli/query": "5.0.0", "@npmcli/redact": "4.0.0", + "@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", @@ -404,11 +414,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": "5.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": "13.0.0", @@ -454,5 +466,9 @@ "onFail": "ignore" } ] + }, + "volta": { + "node": "22.21.0", + "pnpm": "10.19.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 92964b00bf..157661af55 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,6 +39,9 @@ overrides: '@npmcli/package-json': 7.0.2 '@npmcli/query': 5.0.0 '@npmcli/redact': 4.0.0 + '@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 @@ -92,11 +95,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: 5.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: 13.0.0 @@ -286,6 +291,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 @@ -367,11 +378,11 @@ packages: 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': @@ -472,63 +483,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': @@ -617,6 +628,19 @@ 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'} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -679,7 +703,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: '*' @@ -692,7 +716,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==} @@ -716,7 +740,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: @@ -784,11 +808,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: @@ -847,6 +871,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==} @@ -1090,6 +1118,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'} @@ -1128,7 +1160,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: @@ -1354,6 +1386,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} @@ -1414,6 +1449,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'} @@ -1445,6 +1484,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'} @@ -1482,7 +1526,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: '*' @@ -1555,6 +1599,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'} @@ -1617,6 +1664,10 @@ packages: resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} engines: {node: '>=14.16'} + 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'} @@ -1656,6 +1707,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@5.2.0: resolution: {integrity: sha512-xxCJm+Bckc6kQBknN7i9fnP/xobQRsRQxR01CztFkp/h++yfVxUUcmMgfR2HttJx/dpWjS9ubVuyspJv24Q9DA==} engines: {node: '>=20'} @@ -1735,7 +1794,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: @@ -2031,6 +2090,23 @@ 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 + '@types/debug@4.1.12': dependencies: '@types/ms': 2.1.0 @@ -2305,6 +2381,8 @@ snapshots: detect-node@2.1.0: {} + diff@7.0.0: {} + dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -2438,8 +2516,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: {} @@ -2524,7 +2601,6 @@ snapshots: hasown@2.0.2: dependencies: function-bind: 1.1.2 - optional: true hosted-git-info@9.0.2: dependencies: @@ -2586,6 +2662,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: {} @@ -2632,8 +2712,7 @@ snapshots: lodash.truncate@4.4.2: {} - lodash@4.17.21: - optional: true + lodash@4.17.21: {} lowercase-keys@3.0.0: {} @@ -2856,6 +2935,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 +3006,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 +3042,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 +3160,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 +3247,8 @@ snapshots: strip-json-comments@5.0.3: optional: true + supports-preserve-symlinks-flag@1.0.0: {} + table@6.9.0: dependencies: ajv: 8.17.1 @@ -3213,6 +3314,10 @@ snapshots: safe-buffer: 5.2.1 optional: true + type-detect@4.0.8: {} + + type-detect@4.1.0: {} + type-fest@5.2.0: dependencies: tagged-tag: 1.0.0