diff --git a/.github/workflows/analysis.yml b/.github/workflows/analysis.yml index 373cdfde7..1f6e18102 100644 --- a/.github/workflows/analysis.yml +++ b/.github/workflows/analysis.yml @@ -50,3 +50,17 @@ jobs: uses: securego/gosec@master with: args: -exclude=G204,G301,G302,G304,G306 -exclude-dir=\.*test\.* ./... + + ShellCheck: + name: Shellcheck + runs-on: ubuntu-latest + steps: + - name: Checkout Source + uses: actions/checkout@v4 + + - name: Run ShellCheck + uses: ludeeus/action-shellcheck@master + with: + ignore_paths: + .husky + *test* diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 86843c8f7..9c8555826 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -120,16 +120,16 @@ jobs: if: ${{ github.event_name != 'push' }} runs-on: ubuntu-latest steps: - - name: Install Go - uses: actions/setup-go@v3 - with: - go-version: 1.20.x - - name: Checkout code uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} + - name: Install Go + uses: actions/setup-go@v3 + with: + go-version: 1.20.x + - name: Build Frogbot run: buildscripts/build.sh - name: Scan diff --git a/.github/workflows/validate-pr-target-branch.yml b/.github/workflows/validate-pr-target-branch.yml new file mode 100644 index 000000000..1ee921ba9 --- /dev/null +++ b/.github/workflows/validate-pr-target-branch.yml @@ -0,0 +1,19 @@ +name: Validate Pull Request Target Branch + +on: + pull_request_target: + types: + - opened + - reopened + - synchronize + +jobs: + validate-target-branch: + runs-on: ubuntu-latest + steps: + - name: Check Target Branch + run: | + if [ "${{ github.base_ref }}" != "dev" ]; then + echo "Pull requests must target the 'dev' branch." + exit 1 + fi diff --git a/action/.husky/pre-commit b/action/.husky/pre-commit index 9fb8bffcd..ba9122b51 100755 --- a/action/.husky/pre-commit +++ b/action/.husky/pre-commit @@ -2,7 +2,7 @@ . "$(dirname "$0")/_/husky.sh" if [ "$(git status action --porcelain=v1)" ]; then - cd action + cd action || exit npm i npm prune --production git add node_modules lib diff --git a/action/lib/utils.js b/action/lib/utils.js index 0bd6017fd..0cc5a0676 100644 --- a/action/lib/utils.js +++ b/action/lib/utils.js @@ -156,7 +156,8 @@ class Utils { return __awaiter(this, void 0, void 0, function* () { let cliDir = yield (0, tool_cache_1.cacheFile)(downloadDir, fileName, Utils.TOOL_NAME, version); if (!Utils.isWindows()) { - (0, fs_1.chmodSync)((0, path_1.join)(cliDir, fileName), 0o555); + let filePath = (0, path_1.normalize)((0, path_1.join)(cliDir, fileName)); + (0, fs_1.chmodSync)(filePath, 0o555); } core.addPath(cliDir); }); diff --git a/action/node_modules/.package-lock.json b/action/node_modules/.package-lock.json index d5a139759..f0c7170ce 100644 --- a/action/node_modules/.package-lock.json +++ b/action/node_modules/.package-lock.json @@ -6,8 +6,7 @@ "packages": { "node_modules/@actions/core": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", - "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", + "license": "MIT", "dependencies": { "@actions/http-client": "^2.0.1", "uuid": "^8.3.2" @@ -15,24 +14,21 @@ }, "node_modules/@actions/core/node_modules/uuid": { "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/@actions/exec": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", - "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", + "license": "MIT", "dependencies": { "@actions/io": "^1.0.1" } }, "node_modules/@actions/github": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz", - "integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==", + "license": "MIT", "dependencies": { "@actions/http-client": "^2.0.1", "@octokit/core": "^3.6.0", @@ -42,21 +38,18 @@ }, "node_modules/@actions/http-client": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", - "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", + "license": "MIT", "dependencies": { "tunnel": "^0.0.6" } }, "node_modules/@actions/io": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.1.tgz", - "integrity": "sha512-Qi4JoKXjmE0O67wAOH6y0n26QXhMKMFo7GD/4IXNVcrtLjUlGjGuVys6pQgwF3ArfGTQu0XpqaNr0YhED2RaRA==" + "license": "MIT" }, "node_modules/@actions/tool-cache": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-2.0.1.tgz", - "integrity": "sha512-iPU+mNwrbA8jodY8eyo/0S/QqCKDajiR8OxWTnSk/SnYg0sj8Hp4QcUEVC1YFpHWXtrfbQrE13Jz4k4HXJQKcA==", + "license": "MIT", "dependencies": { "@actions/core": "^1.2.6", "@actions/exec": "^1.0.0", @@ -68,29 +61,25 @@ }, "node_modules/@kwsites/file-exists": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", - "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "license": "MIT", "dependencies": { "debug": "^4.1.1" } }, "node_modules/@kwsites/promise-deferred": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", - "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" + "license": "MIT" }, "node_modules/@octokit/auth-token": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", - "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "license": "MIT", "dependencies": { "@octokit/types": "^6.0.3" } }, "node_modules/@octokit/core": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", - "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", + "license": "MIT", "dependencies": { "@octokit/auth-token": "^2.4.4", "@octokit/graphql": "^4.5.8", @@ -103,8 +92,7 @@ }, "node_modules/@octokit/endpoint": { "version": "6.0.12", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", - "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", + "license": "MIT", "dependencies": { "@octokit/types": "^6.0.3", "is-plain-object": "^5.0.0", @@ -113,8 +101,7 @@ }, "node_modules/@octokit/graphql": { "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", - "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "license": "MIT", "dependencies": { "@octokit/request": "^5.6.0", "@octokit/types": "^6.0.3", @@ -123,13 +110,11 @@ }, "node_modules/@octokit/openapi-types": { "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz", - "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==" + "license": "MIT" }, "node_modules/@octokit/plugin-paginate-rest": { "version": "2.17.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz", - "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", + "license": "MIT", "dependencies": { "@octokit/types": "^6.34.0" }, @@ -139,8 +124,7 @@ }, "node_modules/@octokit/plugin-rest-endpoint-methods": { "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz", - "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", + "license": "MIT", "dependencies": { "@octokit/types": "^6.34.0", "deprecation": "^2.3.1" @@ -151,8 +135,7 @@ }, "node_modules/@octokit/request": { "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", - "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", + "license": "MIT", "dependencies": { "@octokit/endpoint": "^6.0.1", "@octokit/request-error": "^2.1.0", @@ -164,8 +147,7 @@ }, "node_modules/@octokit/request-error": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "license": "MIT", "dependencies": { "@octokit/types": "^6.0.3", "deprecation": "^2.0.0", @@ -174,21 +156,18 @@ }, "node_modules/@octokit/types": { "version": "6.34.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz", - "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", + "license": "MIT", "dependencies": { "@octokit/openapi-types": "^11.2.0" } }, "node_modules/before-after-hook": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", - "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==" + "license": "Apache-2.0" }, "node_modules/debug": { "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -203,26 +182,22 @@ }, "node_modules/deprecation": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + "license": "ISC" }, "node_modules/is-plain-object": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/ms": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "license": "MIT" }, "node_modules/node-fetch": { "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -240,18 +215,15 @@ }, "node_modules/node-fetch/node_modules/tr46": { "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "license": "MIT" }, "node_modules/node-fetch/node_modules/webidl-conversions": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "license": "BSD-2-Clause" }, "node_modules/node-fetch/node_modules/whatwg-url": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "license": "MIT", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -259,24 +231,21 @@ }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "license": "ISC", "dependencies": { "wrappy": "1" } }, "node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/simple-git": { "version": "3.19.1", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.19.1.tgz", - "integrity": "sha512-Ck+rcjVaE1HotraRAS8u/+xgTvToTuoMkT9/l9lvuP5jftwnYUp6DwuJzsKErHgfyRk8IB8pqGHWEbM3tLgV1w==", + "license": "MIT", "dependencies": { "@kwsites/file-exists": "^1.1.1", "@kwsites/promise-deferred": "^1.1.1", @@ -289,30 +258,25 @@ }, "node_modules/tunnel": { "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "license": "MIT", "engines": { "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } }, "node_modules/universal-user-agent": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" + "license": "ISC" }, "node_modules/uuid": { "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "license": "MIT", "bin": { "uuid": "bin/uuid" } }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "license": "ISC" } } } diff --git a/action/package-lock.json b/action/package-lock.json index b4167de60..6bd2ef64d 100644 --- a/action/package-lock.json +++ b/action/package-lock.json @@ -45,8 +45,7 @@ }, "node_modules/@actions/core": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", - "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", + "license": "MIT", "dependencies": { "@actions/http-client": "^2.0.1", "uuid": "^8.3.2" @@ -54,24 +53,21 @@ }, "node_modules/@actions/core/node_modules/uuid": { "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/@actions/exec": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", - "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", + "license": "MIT", "dependencies": { "@actions/io": "^1.0.1" } }, "node_modules/@actions/github": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz", - "integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==", + "license": "MIT", "dependencies": { "@actions/http-client": "^2.0.1", "@octokit/core": "^3.6.0", @@ -81,21 +77,18 @@ }, "node_modules/@actions/http-client": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", - "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", + "license": "MIT", "dependencies": { "tunnel": "^0.0.6" } }, "node_modules/@actions/io": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.1.tgz", - "integrity": "sha512-Qi4JoKXjmE0O67wAOH6y0n26QXhMKMFo7GD/4IXNVcrtLjUlGjGuVys6pQgwF3ArfGTQu0XpqaNr0YhED2RaRA==" + "license": "MIT" }, "node_modules/@actions/tool-cache": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-2.0.1.tgz", - "integrity": "sha512-iPU+mNwrbA8jodY8eyo/0S/QqCKDajiR8OxWTnSk/SnYg0sj8Hp4QcUEVC1YFpHWXtrfbQrE13Jz4k4HXJQKcA==", + "license": "MIT", "dependencies": { "@actions/core": "^1.2.6", "@actions/exec": "^1.0.0", @@ -119,12 +112,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.10", + "@babel/highlight": "^7.22.13", "chalk": "^2.4.2" }, "engines": { @@ -203,34 +196,34 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz", + "integrity": "sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.10.tgz", - "integrity": "sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.20.tgz", + "integrity": "sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-compilation-targets": "^7.22.10", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helpers": "^7.22.10", - "@babel/parser": "^7.22.10", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.10", - "@babel/types": "^7.22.10", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.22.15", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.22.20", + "@babel/helpers": "^7.22.15", + "@babel/parser": "^7.22.16", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.22.20", + "@babel/types": "^7.22.19", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", + "json5": "^2.2.3", "semver": "^6.3.1" }, "engines": { @@ -248,12 +241,12 @@ "dev": true }, "node_modules/@babel/generator": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", - "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz", + "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==", "dev": true, "dependencies": { - "@babel/types": "^7.22.10", + "@babel/types": "^7.22.15", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -263,13 +256,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz", - "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", "dev": true, "dependencies": { "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", "browserslist": "^4.21.9", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -279,9 +272,9 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, "engines": { "node": ">=6.9.0" @@ -313,28 +306,28 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", - "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", - "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.20.tgz", + "integrity": "sha512-dLT7JVWIUUxKOs1UnJUBR3S70YK+pKX6AbJgB2vMIvEkZkrfJDbYDJesnPshtKV4LhDOR3Oc5YULeDizRek+5A==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", "@babel/helper-simple-access": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.5" + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -386,44 +379,44 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.10.tgz", - "integrity": "sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.15.tgz", + "integrity": "sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==", "dev": true, "dependencies": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.10", - "@babel/types": "^7.22.10" + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, @@ -503,9 +496,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz", - "integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==", + "version": "7.22.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", + "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -692,33 +685,33 @@ } }, "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz", - "integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.20.tgz", + "integrity": "sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-environment-visitor": "^7.22.5", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.22.5", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.10", - "@babel/types": "^7.22.10", + "@babel/parser": "^7.22.16", + "@babel/types": "^7.22.19", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -736,13 +729,13 @@ } }, "node_modules/@babel/types": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz", - "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==", + "version": "7.22.19", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.19.tgz", + "integrity": "sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.19", "to-fast-properties": "^2.0.0" }, "engines": { @@ -771,9 +764,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", - "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz", + "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -803,18 +796,18 @@ } }, "node_modules/@eslint/js": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", - "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz", + "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -953,16 +946,16 @@ } }, "node_modules/@jest/console": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.6.4.tgz", - "integrity": "sha512-wNK6gC0Ha9QeEPSkeJedQuTQqxZYnDPuDcDhVuVatRvMkL4D0VTvFVZj+Yuh6caG2aOfzkUZ36KtCmLNtR02hw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^29.6.3", - "jest-util": "^29.6.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", "slash": "^3.0.0" }, "engines": { @@ -970,15 +963,15 @@ } }, "node_modules/@jest/core": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.6.4.tgz", - "integrity": "sha512-U/vq5ccNTSVgYH7mHnodHmCffGWHJnz/E1BEWlLuK5pM4FZmGfBn/nrJGLjUsSmyx3otCeqc1T31F4y08AMDLg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, "dependencies": { - "@jest/console": "^29.6.4", - "@jest/reporters": "^29.6.4", - "@jest/test-result": "^29.6.4", - "@jest/transform": "^29.6.4", + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "ansi-escapes": "^4.2.1", @@ -986,21 +979,21 @@ "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.6.3", - "jest-config": "^29.6.4", - "jest-haste-map": "^29.6.4", - "jest-message-util": "^29.6.3", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.6.4", - "jest-resolve-dependencies": "^29.6.4", - "jest-runner": "^29.6.4", - "jest-runtime": "^29.6.4", - "jest-snapshot": "^29.6.4", - "jest-util": "^29.6.3", - "jest-validate": "^29.6.3", - "jest-watcher": "^29.6.4", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", "micromatch": "^4.0.4", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, @@ -1017,37 +1010,37 @@ } }, "node_modules/@jest/environment": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.4.tgz", - "integrity": "sha512-sQ0SULEjA1XUTHmkBRl7A1dyITM9yb1yb3ZNKPX3KlTd6IG7mWUe3e2yfExtC2Zz1Q+mMckOLHmL/qLiuQJrBQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dev": true, "dependencies": { - "@jest/fake-timers": "^29.6.4", + "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", - "jest-mock": "^29.6.3" + "jest-mock": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.6.4.tgz", - "integrity": "sha512-Warhsa7d23+3X5bLbrbYvaehcgX5TLYhI03JKoedTiI8uJU4IhqYBWF7OSSgUyz4IgLpUYPkK0AehA5/fRclAA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, "dependencies": { - "expect": "^29.6.4", - "jest-snapshot": "^29.6.4" + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/expect-utils": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.6.4.tgz", - "integrity": "sha512-FEhkJhqtvBwgSpiTrocquJCdXPsyvNKcl/n7A3u7X4pVoF4bswm11c9d4AV+kfq2Gpv/mM8x7E7DsRvH+djkrg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, "dependencies": { "jest-get-type": "^29.6.3" @@ -1057,47 +1050,47 @@ } }, "node_modules/@jest/fake-timers": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.4.tgz", - "integrity": "sha512-6UkCwzoBK60edXIIWb0/KWkuj7R7Qq91vVInOe3De6DSpaEiqjKcJw4F7XUet24Wupahj9J6PlR09JqJ5ySDHw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dev": true, "dependencies": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "jest-message-util": "^29.6.3", - "jest-mock": "^29.6.3", - "jest-util": "^29.6.3" + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/globals": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.6.4.tgz", - "integrity": "sha512-wVIn5bdtjlChhXAzVXavcY/3PEjf4VqM174BM3eGL5kMxLiZD5CLnbmkEyA1Dwh9q8XjP6E8RwjBsY/iCWrWsA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, "dependencies": { - "@jest/environment": "^29.6.4", - "@jest/expect": "^29.6.4", + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", "@jest/types": "^29.6.3", - "jest-mock": "^29.6.3" + "jest-mock": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/reporters": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.6.4.tgz", - "integrity": "sha512-sxUjWxm7QdchdrD3NfWKrL8FBsortZeibSJv4XLjESOOjSUOkjQcb0ZHJwfhEGIvBvTluTzfG2yZWZhkrXJu8g==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.6.4", - "@jest/test-result": "^29.6.4", - "@jest/transform": "^29.6.4", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "@jridgewell/trace-mapping": "^0.3.18", "@types/node": "*", @@ -1111,9 +1104,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.6.3", - "jest-util": "^29.6.3", - "jest-worker": "^29.6.4", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", @@ -1131,55 +1124,6 @@ } } }, - "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz", - "integrity": "sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@jest/reporters/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@jest/reporters/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@jest/reporters/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@jest/schemas": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", @@ -1207,12 +1151,12 @@ } }, "node_modules/@jest/test-result": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.6.4.tgz", - "integrity": "sha512-uQ1C0AUEN90/dsyEirgMLlouROgSY+Wc/JanVVk0OiUKa5UFh7sJpMEM3aoUBAz2BRNvUJ8j3d294WFuRxSyOQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dev": true, "dependencies": { - "@jest/console": "^29.6.4", + "@jest/console": "^29.7.0", "@jest/types": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" @@ -1222,14 +1166,14 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.6.4.tgz", - "integrity": "sha512-E84M6LbpcRq3fT4ckfKs9ryVanwkaIB0Ws9bw3/yP4seRLg/VaCZ/LgW0MCq5wwk4/iP/qnilD41aj2fsw2RMg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", "dev": true, "dependencies": { - "@jest/test-result": "^29.6.4", + "@jest/test-result": "^29.7.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.6.4", + "jest-haste-map": "^29.7.0", "slash": "^3.0.0" }, "engines": { @@ -1237,9 +1181,9 @@ } }, "node_modules/@jest/transform": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.4.tgz", - "integrity": "sha512-8thgRSiXUqtr/pPGY/OsyHuMjGyhVnWrFAwoxmIemlBuiMyU1WFs0tXoNxzcr4A4uErs/ABre76SGmrr5ab/AA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", @@ -1250,9 +1194,9 @@ "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.6.4", + "jest-haste-map": "^29.7.0", "jest-regex-util": "^29.6.3", - "jest-util": "^29.6.3", + "jest-util": "^29.7.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", @@ -1329,16 +1273,14 @@ }, "node_modules/@kwsites/file-exists": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", - "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "license": "MIT", "dependencies": { "debug": "^4.1.1" } }, "node_modules/@kwsites/promise-deferred": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", - "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" + "license": "MIT" }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", @@ -1377,16 +1319,14 @@ }, "node_modules/@octokit/auth-token": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", - "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "license": "MIT", "dependencies": { "@octokit/types": "^6.0.3" } }, "node_modules/@octokit/core": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", - "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", + "license": "MIT", "dependencies": { "@octokit/auth-token": "^2.4.4", "@octokit/graphql": "^4.5.8", @@ -1399,8 +1339,7 @@ }, "node_modules/@octokit/endpoint": { "version": "6.0.12", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", - "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", + "license": "MIT", "dependencies": { "@octokit/types": "^6.0.3", "is-plain-object": "^5.0.0", @@ -1409,8 +1348,7 @@ }, "node_modules/@octokit/graphql": { "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", - "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "license": "MIT", "dependencies": { "@octokit/request": "^5.6.0", "@octokit/types": "^6.0.3", @@ -1419,13 +1357,11 @@ }, "node_modules/@octokit/openapi-types": { "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz", - "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==" + "license": "MIT" }, "node_modules/@octokit/plugin-paginate-rest": { "version": "2.17.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz", - "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", + "license": "MIT", "dependencies": { "@octokit/types": "^6.34.0" }, @@ -1435,8 +1371,7 @@ }, "node_modules/@octokit/plugin-rest-endpoint-methods": { "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz", - "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", + "license": "MIT", "dependencies": { "@octokit/types": "^6.34.0", "deprecation": "^2.3.1" @@ -1447,8 +1382,7 @@ }, "node_modules/@octokit/request": { "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", - "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", + "license": "MIT", "dependencies": { "@octokit/endpoint": "^6.0.1", "@octokit/request-error": "^2.1.0", @@ -1460,8 +1394,7 @@ }, "node_modules/@octokit/request-error": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "license": "MIT", "dependencies": { "@octokit/types": "^6.0.3", "deprecation": "^2.0.0", @@ -1470,8 +1403,7 @@ }, "node_modules/@octokit/types": { "version": "6.34.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz", - "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", + "license": "MIT", "dependencies": { "@octokit/openapi-types": "^11.2.0" } @@ -1501,9 +1433,9 @@ } }, "node_modules/@types/babel__core": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", - "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", + "integrity": "sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==", "dev": true, "dependencies": { "@babel/parser": "^7.20.7", @@ -1514,18 +1446,18 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.5.tgz", + "integrity": "sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w==", "dev": true, "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.2.tgz", + "integrity": "sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ==", "dev": true, "dependencies": { "@babel/parser": "^7.1.0", @@ -1533,9 +1465,9 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", - "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.2.tgz", + "integrity": "sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" @@ -1575,9 +1507,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.4", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.4.tgz", - "integrity": "sha512-PhglGmhWeD46FYOVLt3X7TiWjzwuVGW9wG/4qocPevXMjCmrIc5b6db9WjeGE4QYVpUAWMDv3v0IiBwObY289A==", + "version": "29.5.5", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.5.tgz", + "integrity": "sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -1585,21 +1517,21 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", + "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", "dev": true }, "node_modules/@types/node": { - "version": "20.5.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.9.tgz", - "integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==", + "version": "20.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz", + "integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==", "dev": true }, "node_modules/@types/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==", "dev": true }, "node_modules/@types/stack-utils": { @@ -1624,16 +1556,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.5.0.tgz", - "integrity": "sha512-2pktILyjvMaScU6iK3925uvGU87E+N9rh372uGZgiMYwafaw9SXq86U04XPq3UH6tzRvNgBsub6x2DacHc33lw==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.2.tgz", + "integrity": "sha512-ooaHxlmSgZTM6CHYAFRlifqh1OAr3PAQEwi7lhYhaegbnXrnh7CDcHmc3+ihhbQC7H0i4JF0psI5ehzkF6Yl6Q==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.5.0", - "@typescript-eslint/type-utils": "6.5.0", - "@typescript-eslint/utils": "6.5.0", - "@typescript-eslint/visitor-keys": "6.5.0", + "@typescript-eslint/scope-manager": "6.7.2", + "@typescript-eslint/type-utils": "6.7.2", + "@typescript-eslint/utils": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1692,15 +1624,15 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.5.0.tgz", - "integrity": "sha512-LMAVtR5GN8nY0G0BadkG0XIe4AcNMeyEy3DyhKGAh9k4pLSMBO7rF29JvDBpZGCmp5Pgz5RLHP6eCpSYZJQDuQ==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.2.tgz", + "integrity": "sha512-KA3E4ox0ws+SPyxQf9iSI25R6b4Ne78ORhNHeVKrPQnoYsb9UhieoiRoJgrzgEeKGOXhcY1i8YtOeCHHTDa6Fw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.5.0", - "@typescript-eslint/types": "6.5.0", - "@typescript-eslint/typescript-estree": "6.5.0", - "@typescript-eslint/visitor-keys": "6.5.0", + "@typescript-eslint/scope-manager": "6.7.2", + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/typescript-estree": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2", "debug": "^4.3.4" }, "engines": { @@ -1720,13 +1652,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.5.0.tgz", - "integrity": "sha512-A8hZ7OlxURricpycp5kdPTH3XnjG85UpJS6Fn4VzeoH4T388gQJ/PGP4ole5NfKt4WDVhmLaQ/dBLNDC4Xl/Kw==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.2.tgz", + "integrity": "sha512-bgi6plgyZjEqapr7u2mhxGR6E8WCzKNUFWNh6fkpVe9+yzRZeYtDTbsIBzKbcxI+r1qVWt6VIoMSNZ4r2A+6Yw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.5.0", - "@typescript-eslint/visitor-keys": "6.5.0" + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1737,13 +1669,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.5.0.tgz", - "integrity": "sha512-f7OcZOkRivtujIBQ4yrJNIuwyCQO1OjocVqntl9dgSIZAdKqicj3xFDqDOzHDlGCZX990LqhLQXWRnQvsapq8A==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.2.tgz", + "integrity": "sha512-36F4fOYIROYRl0qj95dYKx6kybddLtsbmPIYNK0OBeXv2j9L5nZ17j9jmfy+bIDHKQgn2EZX+cofsqi8NPATBQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.5.0", - "@typescript-eslint/utils": "6.5.0", + "@typescript-eslint/typescript-estree": "6.7.2", + "@typescript-eslint/utils": "6.7.2", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1764,9 +1696,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.5.0.tgz", - "integrity": "sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.2.tgz", + "integrity": "sha512-flJYwMYgnUNDAN9/GAI3l8+wTmvTYdv64fcH8aoJK76Y+1FCZ08RtI5zDerM/FYT5DMkAc+19E4aLmd5KqdFyg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1777,13 +1709,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.5.0.tgz", - "integrity": "sha512-q0rGwSe9e5Kk/XzliB9h2LBc9tmXX25G0833r7kffbl5437FPWb2tbpIV9wAATebC/018pGa9fwPDuvGN+LxWQ==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.2.tgz", + "integrity": "sha512-kiJKVMLkoSciGyFU0TOY0fRxnp9qq1AzVOHNeN1+B9erKFCJ4Z8WdjAkKQPP+b1pWStGFqezMLltxO+308dJTQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.5.0", - "@typescript-eslint/visitor-keys": "6.5.0", + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1837,17 +1769,17 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.5.0.tgz", - "integrity": "sha512-9nqtjkNykFzeVtt9Pj6lyR9WEdd8npPhhIPM992FWVkZuS6tmxHfGVnlUcjpUP2hv8r4w35nT33mlxd+Be1ACQ==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.2.tgz", + "integrity": "sha512-ZCcBJug/TS6fXRTsoTkgnsvyWSiXwMNiPzBUani7hDidBdj1779qwM1FIAmpH4lvlOZNF3EScsxxuGifjpLSWQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.5.0", - "@typescript-eslint/types": "6.5.0", - "@typescript-eslint/typescript-estree": "6.5.0", + "@typescript-eslint/scope-manager": "6.7.2", + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/typescript-estree": "6.7.2", "semver": "^7.5.4" }, "engines": { @@ -1895,12 +1827,12 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.5.0.tgz", - "integrity": "sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.2.tgz", + "integrity": "sha512-uVw9VIMFBUTz8rIeaUT3fFe8xIUx8r4ywAdlQv1ifH+6acn/XF8Y6rwJ7XNmkNMDrTW+7+vxFFPIF40nJCVsMQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/types": "6.7.2", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -2028,12 +1960,12 @@ } }, "node_modules/babel-jest": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.6.4.tgz", - "integrity": "sha512-meLj23UlSLddj6PC+YTOFRgDAtjnZom8w/ACsrx0gtPtv5cJZk0A5Unk5bV4wixD7XaPCN1fQvpww8czkZURmw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, "dependencies": { - "@jest/transform": "^29.6.4", + "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", "babel-preset-jest": "^29.6.3", @@ -2064,6 +1996,22 @@ "node": ">=8" } }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/babel-plugin-jest-hoist": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", @@ -2126,8 +2074,7 @@ }, "node_modules/before-after-hook": { "version": "2.2.2", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", - "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==" + "license": "Apache-2.0" }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -2229,9 +2176,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001519", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz", - "integrity": "sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==", + "version": "1.0.30001538", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz", + "integrity": "sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw==", "dev": true, "funding": [ { @@ -2354,6 +2301,27 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2370,8 +2338,7 @@ }, "node_modules/debug": { "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -2415,8 +2382,7 @@ }, "node_modules/deprecation": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + "license": "ISC" }, "node_modules/detect-newline": { "version": "3.1.0", @@ -2461,9 +2427,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.488", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.488.tgz", - "integrity": "sha512-Dv4sTjiW7t/UWGL+H8ZkgIjtUAVZDgb/PwGWvMsCT7jipzUV/u5skbLXPFKb6iV0tiddVi/bcS2/kUrczeWgIQ==", + "version": "1.4.523", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.523.tgz", + "integrity": "sha512-9AreocSUWnzNtvLcbpng6N+GkXnCcBR80IQkxRC9Dfdyg4gaWNUPBujAHUpKkiUkoSoR9UlhA4zD/IgBklmhzg==", "dev": true }, "node_modules/emittery": { @@ -2515,16 +2481,16 @@ } }, "node_modules/eslint": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", - "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz", + "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.48.0", - "@humanwhocodes/config-array": "^0.11.10", + "@eslint/js": "8.49.0", + "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.12.4", @@ -2580,19 +2546,7 @@ "eslint": ">=7.0.0" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { + "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", @@ -2608,13 +2562,16 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { - "node": ">=4.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/espree": { @@ -2659,15 +2616,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -2680,7 +2628,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -2731,16 +2679,16 @@ } }, "node_modules/expect": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.6.4.tgz", - "integrity": "sha512-F2W2UyQ8XYyftHT57dtfg8Ue3X5qLgm2sSug0ivvLRH/VKNRL/pDxg/TH7zVzbQB0tu80clNFy6LU7OS/VSEKA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, "dependencies": { - "@jest/expect-utils": "^29.6.4", + "@jest/expect-utils": "^29.7.0", "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.6.4", - "jest-message-util": "^29.6.3", - "jest-util": "^29.6.3" + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -2851,22 +2799,23 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", + "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", "dev": true, "dependencies": { - "flatted": "^3.1.0", + "flatted": "^3.2.7", + "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=12.0.0" } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, "node_modules/fs.realpath": { @@ -3210,8 +3159,7 @@ }, "node_modules/is-plain-object": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3244,21 +3192,54 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz", + "integrity": "sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==", "dev": true, "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" + "semver": "^7.5.4" }, "engines": { - "node": ">=8" + "node": ">=10" } }, + "node_modules/istanbul-lib-instrument/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", @@ -3301,15 +3282,15 @@ } }, "node_modules/jest": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.6.4.tgz", - "integrity": "sha512-tEFhVQFF/bzoYV1YuGyzLPZ6vlPrdfvDmmAxudA1dLEuiztqg2Rkx20vkKY32xiDROcD2KXlgZ7Cu8RPeEHRKw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "dependencies": { - "@jest/core": "^29.6.4", + "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", "import-local": "^3.0.2", - "jest-cli": "^29.6.4" + "jest-cli": "^29.7.0" }, "bin": { "jest": "bin/jest.js" @@ -3327,13 +3308,13 @@ } }, "node_modules/jest-changed-files": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.6.3.tgz", - "integrity": "sha512-G5wDnElqLa4/c66ma5PG9eRjE342lIbF6SUnTJi26C3J28Fv2TVY2rOyKB9YGbSA5ogwevgmxc4j4aVjrEK6Yg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", "dev": true, "dependencies": { "execa": "^5.0.0", - "jest-util": "^29.6.3", + "jest-util": "^29.7.0", "p-limit": "^3.1.0" }, "engines": { @@ -3341,28 +3322,28 @@ } }, "node_modules/jest-circus": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.6.4.tgz", - "integrity": "sha512-YXNrRyntVUgDfZbjXWBMPslX1mQ8MrSG0oM/Y06j9EYubODIyHWP8hMUbjbZ19M3M+zamqEur7O80HODwACoJw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dev": true, "dependencies": { - "@jest/environment": "^29.6.4", - "@jest/expect": "^29.6.4", - "@jest/test-result": "^29.6.4", + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^1.0.0", "is-generator-fn": "^2.0.0", - "jest-each": "^29.6.3", - "jest-matcher-utils": "^29.6.4", - "jest-message-util": "^29.6.3", - "jest-runtime": "^29.6.4", - "jest-snapshot": "^29.6.4", - "jest-util": "^29.6.3", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", "p-limit": "^3.1.0", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "pure-rand": "^6.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" @@ -3372,22 +3353,21 @@ } }, "node_modules/jest-cli": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.6.4.tgz", - "integrity": "sha512-+uMCQ7oizMmh8ZwRfZzKIEszFY9ksjjEQnTEMTaL7fYiL3Kw4XhqT9bYh+A4DQKUb67hZn2KbtEnDuHvcgK4pQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", "dev": true, "dependencies": { - "@jest/core": "^29.6.4", - "@jest/test-result": "^29.6.4", + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", "chalk": "^4.0.0", + "create-jest": "^29.7.0", "exit": "^0.1.2", - "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^29.6.4", - "jest-util": "^29.6.3", - "jest-validate": "^29.6.3", - "prompts": "^2.0.1", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", "yargs": "^17.3.1" }, "bin": { @@ -3406,31 +3386,31 @@ } }, "node_modules/jest-config": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.6.4.tgz", - "integrity": "sha512-JWohr3i9m2cVpBumQFv2akMEnFEPVOh+9L2xIBJhJ0zOaci2ZXuKJj0tgMKQCBZAKA09H049IR4HVS/43Qb19A==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.6.4", + "@jest/test-sequencer": "^29.7.0", "@jest/types": "^29.6.3", - "babel-jest": "^29.6.4", + "babel-jest": "^29.7.0", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^29.6.4", - "jest-environment-node": "^29.6.4", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", "jest-get-type": "^29.6.3", "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.6.4", - "jest-runner": "^29.6.4", - "jest-util": "^29.6.3", - "jest-validate": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -3451,24 +3431,24 @@ } }, "node_modules/jest-diff": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.4.tgz", - "integrity": "sha512-9F48UxR9e4XOEZvoUXEHSWY4qC4zERJaOfrbBg9JpbJOO43R1vN76REt/aMGZoY6GD5g84nnJiBIVlscegefpw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", "jest-get-type": "^29.6.3", - "pretty-format": "^29.6.3" + "pretty-format": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-docblock": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.6.3.tgz", - "integrity": "sha512-2+H+GOTQBEm2+qFSQ7Ma+BvyV+waiIFxmZF5LdpBsAEjWX8QYjSCa4FrkIYtbfXUJJJnFCYrOtt6TZ+IAiTjBQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dev": true, "dependencies": { "detect-newline": "^3.0.0" @@ -3478,33 +3458,33 @@ } }, "node_modules/jest-each": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.6.3.tgz", - "integrity": "sha512-KoXfJ42k8cqbkfshW7sSHcdfnv5agDdHCPA87ZBdmHP+zJstTJc0ttQaJ/x7zK6noAL76hOuTIJ6ZkQRS5dcyg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", "dev": true, "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", "jest-get-type": "^29.6.3", - "jest-util": "^29.6.3", - "pretty-format": "^29.6.3" + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-environment-node": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.6.4.tgz", - "integrity": "sha512-i7SbpH2dEIFGNmxGCpSc2w9cA4qVD+wfvg2ZnfQ7XVrKL0NA5uDVBIiGH8SR4F0dKEv/0qI5r+aDomDf04DpEQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dev": true, "dependencies": { - "@jest/environment": "^29.6.4", - "@jest/fake-timers": "^29.6.4", + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", - "jest-mock": "^29.6.3", - "jest-util": "^29.6.3" + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3520,9 +3500,9 @@ } }, "node_modules/jest-haste-map": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.4.tgz", - "integrity": "sha512-12Ad+VNTDHxKf7k+M65sviyynRoZYuL1/GTuhEVb8RYsNSNln71nANRb/faSyWvx0j+gHcivChXHIoMJrGYjog==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, "dependencies": { "@jest/types": "^29.6.3", @@ -3532,8 +3512,8 @@ "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.9", "jest-regex-util": "^29.6.3", - "jest-util": "^29.6.3", - "jest-worker": "^29.6.4", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "walker": "^1.0.8" }, @@ -3545,37 +3525,37 @@ } }, "node_modules/jest-leak-detector": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.6.3.tgz", - "integrity": "sha512-0kfbESIHXYdhAdpLsW7xdwmYhLf1BRu4AA118/OxFm0Ho1b2RcTmO4oF6aAMaxpxdxnJ3zve2rgwzNBD4Zbm7Q==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, "dependencies": { "jest-get-type": "^29.6.3", - "pretty-format": "^29.6.3" + "pretty-format": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.6.4.tgz", - "integrity": "sha512-KSzwyzGvK4HcfnserYqJHYi7sZVqdREJ9DMPAKVbS98JsIAvumihaNUbjrWw0St7p9IY7A9UskCW5MYlGmBQFQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^29.6.4", + "jest-diff": "^29.7.0", "jest-get-type": "^29.6.3", - "pretty-format": "^29.6.3" + "pretty-format": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-message-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz", - "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", @@ -3584,7 +3564,7 @@ "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -3593,14 +3573,14 @@ } }, "node_modules/jest-mock": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.3.tgz", - "integrity": "sha512-Z7Gs/mOyTSR4yPsaZ72a/MtuK6RnC3JYqWONe48oLaoEcYwEDxqvbXz85G4SJrm2Z5Ar9zp6MiHF4AlFlRM4Pg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", "dev": true, "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", - "jest-util": "^29.6.3" + "jest-util": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3633,17 +3613,17 @@ } }, "node_modules/jest-resolve": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.6.4.tgz", - "integrity": "sha512-fPRq+0vcxsuGlG0O3gyoqGTAxasagOxEuyoxHeyxaZbc9QNek0AmJWSkhjlMG+mTsj+8knc/mWb3fXlRNVih7Q==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.6.4", + "jest-haste-map": "^29.7.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.6.3", - "jest-validate": "^29.6.3", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", "resolve": "^1.20.0", "resolve.exports": "^2.0.0", "slash": "^3.0.0" @@ -3653,43 +3633,43 @@ } }, "node_modules/jest-resolve-dependencies": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.4.tgz", - "integrity": "sha512-7+6eAmr1ZBF3vOAJVsfLj1QdqeXG+WYhidfLHBRZqGN24MFRIiKG20ItpLw2qRAsW/D2ZUUmCNf6irUr/v6KHA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dev": true, "dependencies": { "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.6.4" + "jest-snapshot": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-runner": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.6.4.tgz", - "integrity": "sha512-SDaLrMmtVlQYDuG0iSPYLycG8P9jLI+fRm8AF/xPKhYDB2g6xDWjXBrR5M8gEWsK6KVFlebpZ4QsrxdyIX1Jaw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, "dependencies": { - "@jest/console": "^29.6.4", - "@jest/environment": "^29.6.4", - "@jest/test-result": "^29.6.4", - "@jest/transform": "^29.6.4", + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.13.1", "graceful-fs": "^4.2.9", - "jest-docblock": "^29.6.3", - "jest-environment-node": "^29.6.4", - "jest-haste-map": "^29.6.4", - "jest-leak-detector": "^29.6.3", - "jest-message-util": "^29.6.3", - "jest-resolve": "^29.6.4", - "jest-runtime": "^29.6.4", - "jest-util": "^29.6.3", - "jest-watcher": "^29.6.4", - "jest-worker": "^29.6.4", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, @@ -3698,17 +3678,17 @@ } }, "node_modules/jest-runtime": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.6.4.tgz", - "integrity": "sha512-s/QxMBLvmwLdchKEjcLfwzP7h+jsHvNEtxGP5P+Fl1FMaJX2jMiIqe4rJw4tFprzCwuSvVUo9bn0uj4gNRXsbA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", "dev": true, "dependencies": { - "@jest/environment": "^29.6.4", - "@jest/fake-timers": "^29.6.4", - "@jest/globals": "^29.6.4", + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.6.4", - "@jest/transform": "^29.6.4", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", @@ -3716,13 +3696,13 @@ "collect-v8-coverage": "^1.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.6.4", - "jest-message-util": "^29.6.3", - "jest-mock": "^29.6.3", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.6.4", - "jest-snapshot": "^29.6.4", - "jest-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -3731,9 +3711,9 @@ } }, "node_modules/jest-snapshot": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.6.4.tgz", - "integrity": "sha512-VC1N8ED7+4uboUKGIDsbvNAZb6LakgIPgAF4RSpF13dN6YaMokfRqO+BaqK4zIh6X3JffgwbzuGqDEjHm/MrvA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, "dependencies": { "@babel/core": "^7.11.6", @@ -3741,20 +3721,20 @@ "@babel/plugin-syntax-jsx": "^7.7.2", "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.6.4", - "@jest/transform": "^29.6.4", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^29.6.4", + "expect": "^29.7.0", "graceful-fs": "^4.2.9", - "jest-diff": "^29.6.4", + "jest-diff": "^29.7.0", "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.6.4", - "jest-message-util": "^29.6.3", - "jest-util": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", "natural-compare": "^1.4.0", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "semver": "^7.5.3" }, "engines": { @@ -3795,9 +3775,9 @@ "dev": true }, "node_modules/jest-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", - "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, "dependencies": { "@jest/types": "^29.6.3", @@ -3812,9 +3792,9 @@ } }, "node_modules/jest-validate": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.6.3.tgz", - "integrity": "sha512-e7KWZcAIX+2W1o3cHfnqpGajdCs1jSM3DkXjGeLSNmCazv1EeI1ggTeK5wdZhF+7N+g44JI2Od3veojoaumlfg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, "dependencies": { "@jest/types": "^29.6.3", @@ -3822,7 +3802,7 @@ "chalk": "^4.0.0", "jest-get-type": "^29.6.3", "leven": "^3.1.0", - "pretty-format": "^29.6.3" + "pretty-format": "^29.7.0" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3841,18 +3821,18 @@ } }, "node_modules/jest-watcher": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.6.4.tgz", - "integrity": "sha512-oqUWvx6+On04ShsT00Ir9T4/FvBeEh2M9PTubgITPxDa739p4hoQweWPRGyYeaojgT0xTpZKF0Y/rSY1UgMxvQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dev": true, "dependencies": { - "@jest/test-result": "^29.6.4", + "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.13.1", - "jest-util": "^29.6.3", + "jest-util": "^29.7.0", "string-length": "^4.0.1" }, "engines": { @@ -3860,13 +3840,13 @@ } }, "node_modules/jest-worker": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.4.tgz", - "integrity": "sha512-6dpvFV4WjcWbDVGgHTWo/aupl8/LbBx2NSKfiwqf79xC/yeJjKHT1+StcKy/2KTmW16hE68ccKVOtXf+WZGz7Q==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, "dependencies": { "@types/node": "*", - "jest-util": "^29.6.3", + "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, @@ -3919,6 +3899,12 @@ "node": ">=4" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -3949,6 +3935,15 @@ "node": ">=6" } }, + "node_modules/keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -4136,8 +4131,7 @@ }, "node_modules/ms": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "license": "MIT" }, "node_modules/natural-compare": { "version": "1.4.0", @@ -4147,8 +4141,7 @@ }, "node_modules/node-fetch": { "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -4166,18 +4159,15 @@ }, "node_modules/node-fetch/node_modules/tr46": { "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "license": "MIT" }, "node_modules/node-fetch/node_modules/webidl-conversions": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "license": "BSD-2-Clause" }, "node_modules/node-fetch/node_modules/whatwg-url": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "license": "MIT", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -4218,8 +4208,7 @@ }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -4483,9 +4472,9 @@ } }, "node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "dependencies": { "@jest/schemas": "^29.6.3", @@ -4531,9 +4520,9 @@ } }, "node_modules/pure-rand": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", - "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.3.tgz", + "integrity": "sha512-KddyFewCsO0j3+np81IQ+SweXLDnDQTs5s67BOnrYmYe/yNmUhttQyGsYzy8yUnoljGAQ9sl38YB4vH8ur7Y+w==", "dev": true, "funding": [ { @@ -4582,9 +4571,9 @@ } }, "node_modules/resolve": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", - "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "version": "1.22.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", + "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", "dev": true, "dependencies": { "is-core-module": "^2.13.0", @@ -4687,8 +4676,7 @@ }, "node_modules/semver": { "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -4722,8 +4710,7 @@ }, "node_modules/simple-git": { "version": "3.19.1", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.19.1.tgz", - "integrity": "sha512-Ck+rcjVaE1HotraRAS8u/+xgTvToTuoMkT9/l9lvuP5jftwnYUp6DwuJzsKErHgfyRk8IB8pqGHWEbM3tLgV1w==", + "license": "MIT", "dependencies": { "@kwsites/file-exists": "^1.1.1", "@kwsites/promise-deferred": "^1.1.1", @@ -4936,9 +4923,9 @@ } }, "node_modules/ts-api-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", - "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", "dev": true, "engines": { "node": ">=16.13.0" @@ -5025,8 +5012,7 @@ }, "node_modules/tunnel": { "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "license": "MIT", "engines": { "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } @@ -5079,8 +5065,7 @@ }, "node_modules/universal-user-agent": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" + "license": "ISC" }, "node_modules/update-browserslist-db": { "version": "1.0.11", @@ -5123,9 +5108,7 @@ }, "node_modules/uuid": { "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "license": "MIT", "bin": { "uuid": "bin/uuid" } @@ -5193,8 +5176,7 @@ }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "license": "ISC" }, "node_modules/write-file-atomic": { "version": "4.0.2", @@ -5273,32 +5255,24 @@ }, "@actions/core": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", - "integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==", "requires": { "@actions/http-client": "^2.0.1", "uuid": "^8.3.2" }, "dependencies": { "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + "version": "8.3.2" } } }, "@actions/exec": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", - "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", "requires": { "@actions/io": "^1.0.1" } }, "@actions/github": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz", - "integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==", "requires": { "@actions/http-client": "^2.0.1", "@octokit/core": "^3.6.0", @@ -5308,21 +5282,15 @@ }, "@actions/http-client": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", - "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", "requires": { "tunnel": "^0.0.6" } }, "@actions/io": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.1.tgz", - "integrity": "sha512-Qi4JoKXjmE0O67wAOH6y0n26QXhMKMFo7GD/4IXNVcrtLjUlGjGuVys6pQgwF3ArfGTQu0XpqaNr0YhED2RaRA==" + "version": "1.1.1" }, "@actions/tool-cache": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-2.0.1.tgz", - "integrity": "sha512-iPU+mNwrbA8jodY8eyo/0S/QqCKDajiR8OxWTnSk/SnYg0sj8Hp4QcUEVC1YFpHWXtrfbQrE13Jz4k4HXJQKcA==", "requires": { "@actions/core": "^1.2.6", "@actions/exec": "^1.0.0", @@ -5343,12 +5311,12 @@ } }, "@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "requires": { - "@babel/highlight": "^7.22.10", + "@babel/highlight": "^7.22.13", "chalk": "^2.4.2" }, "dependencies": { @@ -5411,31 +5379,31 @@ } }, "@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz", + "integrity": "sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==", "dev": true }, "@babel/core": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.10.tgz", - "integrity": "sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.20.tgz", + "integrity": "sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA==", "dev": true, "requires": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-compilation-targets": "^7.22.10", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helpers": "^7.22.10", - "@babel/parser": "^7.22.10", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.10", - "@babel/types": "^7.22.10", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.22.15", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.22.20", + "@babel/helpers": "^7.22.15", + "@babel/parser": "^7.22.16", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.22.20", + "@babel/types": "^7.22.19", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", + "json5": "^2.2.3", "semver": "^6.3.1" }, "dependencies": { @@ -5448,34 +5416,34 @@ } }, "@babel/generator": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", - "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz", + "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==", "dev": true, "requires": { - "@babel/types": "^7.22.10", + "@babel/types": "^7.22.15", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" } }, "@babel/helper-compilation-targets": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz", - "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", "dev": true, "requires": { "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", "browserslist": "^4.21.9", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true }, "@babel/helper-function-name": { @@ -5498,25 +5466,25 @@ } }, "@babel/helper-module-imports": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", - "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dev": true, "requires": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.15" } }, "@babel/helper-module-transforms": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", - "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.20.tgz", + "integrity": "sha512-dLT7JVWIUUxKOs1UnJUBR3S70YK+pKX6AbJgB2vMIvEkZkrfJDbYDJesnPshtKV4LhDOR3Oc5YULeDizRek+5A==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", "@babel/helper-simple-access": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.5" + "@babel/helper-validator-identifier": "^7.22.20" } }, "@babel/helper-plugin-utils": { @@ -5550,35 +5518,35 @@ "dev": true }, "@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", "dev": true }, "@babel/helpers": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.10.tgz", - "integrity": "sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.15.tgz", + "integrity": "sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==", "dev": true, "requires": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.10", - "@babel/types": "^7.22.10" + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, @@ -5642,9 +5610,9 @@ } }, "@babel/parser": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz", - "integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==", + "version": "7.22.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", + "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -5774,30 +5742,30 @@ } }, "@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz", - "integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.20.tgz", + "integrity": "sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==", "dev": true, "requires": { - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-environment-visitor": "^7.22.5", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.22.5", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.10", - "@babel/types": "^7.22.10", + "@babel/parser": "^7.22.16", + "@babel/types": "^7.22.19", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -5811,13 +5779,13 @@ } }, "@babel/types": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz", - "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==", + "version": "7.22.19", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.19.tgz", + "integrity": "sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.19", "to-fast-properties": "^2.0.0" } }, @@ -5837,9 +5805,9 @@ } }, "@eslint-community/regexpp": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", - "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz", + "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==", "dev": true }, "@eslint/eslintrc": { @@ -5860,15 +5828,15 @@ } }, "@eslint/js": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", - "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz", + "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==", "dev": true }, "@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -5972,29 +5940,29 @@ "dev": true }, "@jest/console": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.6.4.tgz", - "integrity": "sha512-wNK6gC0Ha9QeEPSkeJedQuTQqxZYnDPuDcDhVuVatRvMkL4D0VTvFVZj+Yuh6caG2aOfzkUZ36KtCmLNtR02hw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, "requires": { "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^29.6.3", - "jest-util": "^29.6.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", "slash": "^3.0.0" } }, "@jest/core": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.6.4.tgz", - "integrity": "sha512-U/vq5ccNTSVgYH7mHnodHmCffGWHJnz/E1BEWlLuK5pM4FZmGfBn/nrJGLjUsSmyx3otCeqc1T31F4y08AMDLg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, "requires": { - "@jest/console": "^29.6.4", - "@jest/reporters": "^29.6.4", - "@jest/test-result": "^29.6.4", - "@jest/transform": "^29.6.4", + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "ansi-escapes": "^4.2.1", @@ -6002,92 +5970,92 @@ "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.6.3", - "jest-config": "^29.6.4", - "jest-haste-map": "^29.6.4", - "jest-message-util": "^29.6.3", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.6.4", - "jest-resolve-dependencies": "^29.6.4", - "jest-runner": "^29.6.4", - "jest-runtime": "^29.6.4", - "jest-snapshot": "^29.6.4", - "jest-util": "^29.6.3", - "jest-validate": "^29.6.3", - "jest-watcher": "^29.6.4", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", "micromatch": "^4.0.4", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" } }, "@jest/environment": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.6.4.tgz", - "integrity": "sha512-sQ0SULEjA1XUTHmkBRl7A1dyITM9yb1yb3ZNKPX3KlTd6IG7mWUe3e2yfExtC2Zz1Q+mMckOLHmL/qLiuQJrBQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dev": true, "requires": { - "@jest/fake-timers": "^29.6.4", + "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", - "jest-mock": "^29.6.3" + "jest-mock": "^29.7.0" } }, "@jest/expect": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.6.4.tgz", - "integrity": "sha512-Warhsa7d23+3X5bLbrbYvaehcgX5TLYhI03JKoedTiI8uJU4IhqYBWF7OSSgUyz4IgLpUYPkK0AehA5/fRclAA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, "requires": { - "expect": "^29.6.4", - "jest-snapshot": "^29.6.4" + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" } }, "@jest/expect-utils": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.6.4.tgz", - "integrity": "sha512-FEhkJhqtvBwgSpiTrocquJCdXPsyvNKcl/n7A3u7X4pVoF4bswm11c9d4AV+kfq2Gpv/mM8x7E7DsRvH+djkrg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, "requires": { "jest-get-type": "^29.6.3" } }, "@jest/fake-timers": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.6.4.tgz", - "integrity": "sha512-6UkCwzoBK60edXIIWb0/KWkuj7R7Qq91vVInOe3De6DSpaEiqjKcJw4F7XUet24Wupahj9J6PlR09JqJ5ySDHw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dev": true, "requires": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "jest-message-util": "^29.6.3", - "jest-mock": "^29.6.3", - "jest-util": "^29.6.3" + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" } }, "@jest/globals": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.6.4.tgz", - "integrity": "sha512-wVIn5bdtjlChhXAzVXavcY/3PEjf4VqM174BM3eGL5kMxLiZD5CLnbmkEyA1Dwh9q8XjP6E8RwjBsY/iCWrWsA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, "requires": { - "@jest/environment": "^29.6.4", - "@jest/expect": "^29.6.4", + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", "@jest/types": "^29.6.3", - "jest-mock": "^29.6.3" + "jest-mock": "^29.7.0" } }, "@jest/reporters": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.6.4.tgz", - "integrity": "sha512-sxUjWxm7QdchdrD3NfWKrL8FBsortZeibSJv4XLjESOOjSUOkjQcb0ZHJwfhEGIvBvTluTzfG2yZWZhkrXJu8g==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.6.4", - "@jest/test-result": "^29.6.4", - "@jest/transform": "^29.6.4", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "@jridgewell/trace-mapping": "^0.3.18", "@types/node": "*", @@ -6101,52 +6069,13 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.6.3", - "jest-util": "^29.6.3", - "jest-worker": "^29.6.4", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", "slash": "^3.0.0", "string-length": "^4.0.1", "strip-ansi": "^6.0.0", "v8-to-istanbul": "^9.0.1" - }, - "dependencies": { - "istanbul-lib-instrument": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz", - "integrity": "sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } } }, "@jest/schemas": { @@ -6170,33 +6099,33 @@ } }, "@jest/test-result": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.6.4.tgz", - "integrity": "sha512-uQ1C0AUEN90/dsyEirgMLlouROgSY+Wc/JanVVk0OiUKa5UFh7sJpMEM3aoUBAz2BRNvUJ8j3d294WFuRxSyOQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dev": true, "requires": { - "@jest/console": "^29.6.4", + "@jest/console": "^29.7.0", "@jest/types": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.6.4.tgz", - "integrity": "sha512-E84M6LbpcRq3fT4ckfKs9ryVanwkaIB0Ws9bw3/yP4seRLg/VaCZ/LgW0MCq5wwk4/iP/qnilD41aj2fsw2RMg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", "dev": true, "requires": { - "@jest/test-result": "^29.6.4", + "@jest/test-result": "^29.7.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.6.4", + "jest-haste-map": "^29.7.0", "slash": "^3.0.0" } }, "@jest/transform": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.6.4.tgz", - "integrity": "sha512-8thgRSiXUqtr/pPGY/OsyHuMjGyhVnWrFAwoxmIemlBuiMyU1WFs0tXoNxzcr4A4uErs/ABre76SGmrr5ab/AA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, "requires": { "@babel/core": "^7.11.6", @@ -6207,9 +6136,9 @@ "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.6.4", + "jest-haste-map": "^29.7.0", "jest-regex-util": "^29.6.3", - "jest-util": "^29.6.3", + "jest-util": "^29.7.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", @@ -6271,16 +6200,12 @@ }, "@kwsites/file-exists": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", - "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", "requires": { "debug": "^4.1.1" } }, "@kwsites/promise-deferred": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", - "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" + "version": "1.1.1" }, "@nodelib/fs.scandir": { "version": "2.1.5", @@ -6310,16 +6235,12 @@ }, "@octokit/auth-token": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", - "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", "requires": { "@octokit/types": "^6.0.3" } }, "@octokit/core": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", - "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", "requires": { "@octokit/auth-token": "^2.4.4", "@octokit/graphql": "^4.5.8", @@ -6332,8 +6253,6 @@ }, "@octokit/endpoint": { "version": "6.0.12", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", - "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", "requires": { "@octokit/types": "^6.0.3", "is-plain-object": "^5.0.0", @@ -6342,8 +6261,6 @@ }, "@octokit/graphql": { "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", - "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", "requires": { "@octokit/request": "^5.6.0", "@octokit/types": "^6.0.3", @@ -6351,22 +6268,16 @@ } }, "@octokit/openapi-types": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz", - "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==" + "version": "11.2.0" }, "@octokit/plugin-paginate-rest": { "version": "2.17.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz", - "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", "requires": { "@octokit/types": "^6.34.0" } }, "@octokit/plugin-rest-endpoint-methods": { "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz", - "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", "requires": { "@octokit/types": "^6.34.0", "deprecation": "^2.3.1" @@ -6374,8 +6285,6 @@ }, "@octokit/request": { "version": "5.6.3", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", - "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", "requires": { "@octokit/endpoint": "^6.0.1", "@octokit/request-error": "^2.1.0", @@ -6387,8 +6296,6 @@ }, "@octokit/request-error": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", - "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", "requires": { "@octokit/types": "^6.0.3", "deprecation": "^2.0.0", @@ -6397,8 +6304,6 @@ }, "@octokit/types": { "version": "6.34.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz", - "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", "requires": { "@octokit/openapi-types": "^11.2.0" } @@ -6428,9 +6333,9 @@ } }, "@types/babel__core": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", - "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", + "integrity": "sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA==", "dev": true, "requires": { "@babel/parser": "^7.20.7", @@ -6441,18 +6346,18 @@ } }, "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.5.tgz", + "integrity": "sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w==", "dev": true, "requires": { "@babel/types": "^7.0.0" } }, "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.2.tgz", + "integrity": "sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -6460,9 +6365,9 @@ } }, "@types/babel__traverse": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", - "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.2.tgz", + "integrity": "sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw==", "dev": true, "requires": { "@babel/types": "^7.20.7" @@ -6502,9 +6407,9 @@ } }, "@types/jest": { - "version": "29.5.4", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.4.tgz", - "integrity": "sha512-PhglGmhWeD46FYOVLt3X7TiWjzwuVGW9wG/4qocPevXMjCmrIc5b6db9WjeGE4QYVpUAWMDv3v0IiBwObY289A==", + "version": "29.5.5", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.5.tgz", + "integrity": "sha512-ebylz2hnsWR9mYvmBFbXJXr+33UPc4+ZdxyDXh5w0FlPBTfCVN3wPL+kuOiQt3xvrK419v7XWeAs+AeOksafXg==", "dev": true, "requires": { "expect": "^29.0.0", @@ -6512,21 +6417,21 @@ } }, "@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", + "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", "dev": true }, "@types/node": { - "version": "20.5.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.9.tgz", - "integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==", + "version": "20.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.2.tgz", + "integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==", "dev": true }, "@types/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==", + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==", "dev": true }, "@types/stack-utils": { @@ -6551,16 +6456,16 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.5.0.tgz", - "integrity": "sha512-2pktILyjvMaScU6iK3925uvGU87E+N9rh372uGZgiMYwafaw9SXq86U04XPq3UH6tzRvNgBsub6x2DacHc33lw==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.2.tgz", + "integrity": "sha512-ooaHxlmSgZTM6CHYAFRlifqh1OAr3PAQEwi7lhYhaegbnXrnh7CDcHmc3+ihhbQC7H0i4JF0psI5ehzkF6Yl6Q==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.5.0", - "@typescript-eslint/type-utils": "6.5.0", - "@typescript-eslint/utils": "6.5.0", - "@typescript-eslint/visitor-keys": "6.5.0", + "@typescript-eslint/scope-manager": "6.7.2", + "@typescript-eslint/type-utils": "6.7.2", + "@typescript-eslint/utils": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -6596,54 +6501,54 @@ } }, "@typescript-eslint/parser": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.5.0.tgz", - "integrity": "sha512-LMAVtR5GN8nY0G0BadkG0XIe4AcNMeyEy3DyhKGAh9k4pLSMBO7rF29JvDBpZGCmp5Pgz5RLHP6eCpSYZJQDuQ==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.2.tgz", + "integrity": "sha512-KA3E4ox0ws+SPyxQf9iSI25R6b4Ne78ORhNHeVKrPQnoYsb9UhieoiRoJgrzgEeKGOXhcY1i8YtOeCHHTDa6Fw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "6.5.0", - "@typescript-eslint/types": "6.5.0", - "@typescript-eslint/typescript-estree": "6.5.0", - "@typescript-eslint/visitor-keys": "6.5.0", + "@typescript-eslint/scope-manager": "6.7.2", + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/typescript-estree": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.5.0.tgz", - "integrity": "sha512-A8hZ7OlxURricpycp5kdPTH3XnjG85UpJS6Fn4VzeoH4T388gQJ/PGP4ole5NfKt4WDVhmLaQ/dBLNDC4Xl/Kw==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.2.tgz", + "integrity": "sha512-bgi6plgyZjEqapr7u2mhxGR6E8WCzKNUFWNh6fkpVe9+yzRZeYtDTbsIBzKbcxI+r1qVWt6VIoMSNZ4r2A+6Yw==", "dev": true, "requires": { - "@typescript-eslint/types": "6.5.0", - "@typescript-eslint/visitor-keys": "6.5.0" + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2" } }, "@typescript-eslint/type-utils": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.5.0.tgz", - "integrity": "sha512-f7OcZOkRivtujIBQ4yrJNIuwyCQO1OjocVqntl9dgSIZAdKqicj3xFDqDOzHDlGCZX990LqhLQXWRnQvsapq8A==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.2.tgz", + "integrity": "sha512-36F4fOYIROYRl0qj95dYKx6kybddLtsbmPIYNK0OBeXv2j9L5nZ17j9jmfy+bIDHKQgn2EZX+cofsqi8NPATBQ==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "6.5.0", - "@typescript-eslint/utils": "6.5.0", + "@typescript-eslint/typescript-estree": "6.7.2", + "@typescript-eslint/utils": "6.7.2", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" } }, "@typescript-eslint/types": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.5.0.tgz", - "integrity": "sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.2.tgz", + "integrity": "sha512-flJYwMYgnUNDAN9/GAI3l8+wTmvTYdv64fcH8aoJK76Y+1FCZ08RtI5zDerM/FYT5DMkAc+19E4aLmd5KqdFyg==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.5.0.tgz", - "integrity": "sha512-q0rGwSe9e5Kk/XzliB9h2LBc9tmXX25G0833r7kffbl5437FPWb2tbpIV9wAATebC/018pGa9fwPDuvGN+LxWQ==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.2.tgz", + "integrity": "sha512-kiJKVMLkoSciGyFU0TOY0fRxnp9qq1AzVOHNeN1+B9erKFCJ4Z8WdjAkKQPP+b1pWStGFqezMLltxO+308dJTQ==", "dev": true, "requires": { - "@typescript-eslint/types": "6.5.0", - "@typescript-eslint/visitor-keys": "6.5.0", + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/visitor-keys": "6.7.2", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6678,17 +6583,17 @@ } }, "@typescript-eslint/utils": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.5.0.tgz", - "integrity": "sha512-9nqtjkNykFzeVtt9Pj6lyR9WEdd8npPhhIPM992FWVkZuS6tmxHfGVnlUcjpUP2hv8r4w35nT33mlxd+Be1ACQ==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.2.tgz", + "integrity": "sha512-ZCcBJug/TS6fXRTsoTkgnsvyWSiXwMNiPzBUani7hDidBdj1779qwM1FIAmpH4lvlOZNF3EScsxxuGifjpLSWQ==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.5.0", - "@typescript-eslint/types": "6.5.0", - "@typescript-eslint/typescript-estree": "6.5.0", + "@typescript-eslint/scope-manager": "6.7.2", + "@typescript-eslint/types": "6.7.2", + "@typescript-eslint/typescript-estree": "6.7.2", "semver": "^7.5.4" }, "dependencies": { @@ -6719,12 +6624,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.5.0.tgz", - "integrity": "sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.2.tgz", + "integrity": "sha512-uVw9VIMFBUTz8rIeaUT3fFe8xIUx8r4ywAdlQv1ifH+6acn/XF8Y6rwJ7XNmkNMDrTW+7+vxFFPIF40nJCVsMQ==", "dev": true, "requires": { - "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/types": "6.7.2", "eslint-visitor-keys": "^3.4.1" } }, @@ -6808,12 +6713,12 @@ "dev": true }, "babel-jest": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.6.4.tgz", - "integrity": "sha512-meLj23UlSLddj6PC+YTOFRgDAtjnZom8w/ACsrx0gtPtv5cJZk0A5Unk5bV4wixD7XaPCN1fQvpww8czkZURmw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, "requires": { - "@jest/transform": "^29.6.4", + "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", "babel-preset-jest": "^29.6.3", @@ -6833,6 +6738,21 @@ "@istanbuljs/schema": "^0.1.2", "istanbul-lib-instrument": "^5.0.4", "test-exclude": "^6.0.0" + }, + "dependencies": { + "istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + } } }, "babel-plugin-jest-hoist": { @@ -6884,9 +6804,7 @@ "dev": true }, "before-after-hook": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", - "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==" + "version": "2.2.2" }, "brace-expansion": { "version": "1.1.11", @@ -6956,9 +6874,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001519", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz", - "integrity": "sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg==", + "version": "1.0.30001538", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz", + "integrity": "sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw==", "dev": true }, "chalk": { @@ -7039,6 +6957,21 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "requires": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -7052,8 +6985,6 @@ }, "debug": { "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } @@ -7078,9 +7009,7 @@ "dev": true }, "deprecation": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + "version": "2.3.1" }, "detect-newline": { "version": "3.1.0", @@ -7113,9 +7042,9 @@ } }, "electron-to-chromium": { - "version": "1.4.488", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.488.tgz", - "integrity": "sha512-Dv4sTjiW7t/UWGL+H8ZkgIjtUAVZDgb/PwGWvMsCT7jipzUV/u5skbLXPFKb6iV0tiddVi/bcS2/kUrczeWgIQ==", + "version": "1.4.523", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.523.tgz", + "integrity": "sha512-9AreocSUWnzNtvLcbpng6N+GkXnCcBR80IQkxRC9Dfdyg4gaWNUPBujAHUpKkiUkoSoR9UlhA4zD/IgBklmhzg==", "dev": true }, "emittery": { @@ -7152,16 +7081,16 @@ "dev": true }, "eslint": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", - "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz", + "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.48.0", - "@humanwhocodes/config-array": "^0.11.10", + "@eslint/js": "8.49.0", + "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.12.4", @@ -7194,24 +7123,6 @@ "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "text-table": "^0.2.0" - }, - "dependencies": { - "eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } } }, "eslint-config-prettier": { @@ -7221,6 +7132,16 @@ "dev": true, "requires": {} }, + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, "eslint-visitor-keys": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", @@ -7251,14 +7172,6 @@ "dev": true, "requires": { "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } } }, "esrecurse": { @@ -7268,16 +7181,14 @@ "dev": true, "requires": { "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } } }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -7308,16 +7219,16 @@ "dev": true }, "expect": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.6.4.tgz", - "integrity": "sha512-F2W2UyQ8XYyftHT57dtfg8Ue3X5qLgm2sSug0ivvLRH/VKNRL/pDxg/TH7zVzbQB0tu80clNFy6LU7OS/VSEKA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, "requires": { - "@jest/expect-utils": "^29.6.4", + "@jest/expect-utils": "^29.7.0", "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.6.4", - "jest-message-util": "^29.6.3", - "jest-util": "^29.6.3" + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" } }, "fast-deep-equal": { @@ -7409,19 +7320,20 @@ } }, "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", + "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", "dev": true, "requires": { - "flatted": "^3.1.0", + "flatted": "^3.2.7", + "keyv": "^4.5.3", "rimraf": "^3.0.2" } }, "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, "fs.realpath": { @@ -7661,9 +7573,7 @@ "dev": true }, "is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + "version": "5.0.0" }, "is-stream": { "version": "2.0.1", @@ -7684,16 +7594,42 @@ "dev": true }, "istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.0.tgz", + "integrity": "sha512-x58orMzEVfzPUKqlbLd1hXCnySCxKdDKa6Rjg97CwuLLRI4g3FHTdnExu1OqffVFay6zeMW+T6/DowFLndWnIw==", "dev": true, "requires": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" + "semver": "^7.5.4" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } } }, "istanbul-lib-report": { @@ -7729,152 +7665,151 @@ } }, "jest": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.6.4.tgz", - "integrity": "sha512-tEFhVQFF/bzoYV1YuGyzLPZ6vlPrdfvDmmAxudA1dLEuiztqg2Rkx20vkKY32xiDROcD2KXlgZ7Cu8RPeEHRKw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "requires": { - "@jest/core": "^29.6.4", + "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", "import-local": "^3.0.2", - "jest-cli": "^29.6.4" + "jest-cli": "^29.7.0" } }, "jest-changed-files": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.6.3.tgz", - "integrity": "sha512-G5wDnElqLa4/c66ma5PG9eRjE342lIbF6SUnTJi26C3J28Fv2TVY2rOyKB9YGbSA5ogwevgmxc4j4aVjrEK6Yg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", "dev": true, "requires": { "execa": "^5.0.0", - "jest-util": "^29.6.3", + "jest-util": "^29.7.0", "p-limit": "^3.1.0" } }, "jest-circus": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.6.4.tgz", - "integrity": "sha512-YXNrRyntVUgDfZbjXWBMPslX1mQ8MrSG0oM/Y06j9EYubODIyHWP8hMUbjbZ19M3M+zamqEur7O80HODwACoJw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dev": true, "requires": { - "@jest/environment": "^29.6.4", - "@jest/expect": "^29.6.4", - "@jest/test-result": "^29.6.4", + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^1.0.0", "is-generator-fn": "^2.0.0", - "jest-each": "^29.6.3", - "jest-matcher-utils": "^29.6.4", - "jest-message-util": "^29.6.3", - "jest-runtime": "^29.6.4", - "jest-snapshot": "^29.6.4", - "jest-util": "^29.6.3", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", "p-limit": "^3.1.0", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "pure-rand": "^6.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" } }, "jest-cli": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.6.4.tgz", - "integrity": "sha512-+uMCQ7oizMmh8ZwRfZzKIEszFY9ksjjEQnTEMTaL7fYiL3Kw4XhqT9bYh+A4DQKUb67hZn2KbtEnDuHvcgK4pQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", "dev": true, "requires": { - "@jest/core": "^29.6.4", - "@jest/test-result": "^29.6.4", + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", "chalk": "^4.0.0", + "create-jest": "^29.7.0", "exit": "^0.1.2", - "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^29.6.4", - "jest-util": "^29.6.3", - "jest-validate": "^29.6.3", - "prompts": "^2.0.1", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", "yargs": "^17.3.1" } }, "jest-config": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.6.4.tgz", - "integrity": "sha512-JWohr3i9m2cVpBumQFv2akMEnFEPVOh+9L2xIBJhJ0zOaci2ZXuKJj0tgMKQCBZAKA09H049IR4HVS/43Qb19A==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", "dev": true, "requires": { "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.6.4", + "@jest/test-sequencer": "^29.7.0", "@jest/types": "^29.6.3", - "babel-jest": "^29.6.4", + "babel-jest": "^29.7.0", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^29.6.4", - "jest-environment-node": "^29.6.4", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", "jest-get-type": "^29.6.3", "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.6.4", - "jest-runner": "^29.6.4", - "jest-util": "^29.6.3", - "jest-validate": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" } }, "jest-diff": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.6.4.tgz", - "integrity": "sha512-9F48UxR9e4XOEZvoUXEHSWY4qC4zERJaOfrbBg9JpbJOO43R1vN76REt/aMGZoY6GD5g84nnJiBIVlscegefpw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, "requires": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", "jest-get-type": "^29.6.3", - "pretty-format": "^29.6.3" + "pretty-format": "^29.7.0" } }, "jest-docblock": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.6.3.tgz", - "integrity": "sha512-2+H+GOTQBEm2+qFSQ7Ma+BvyV+waiIFxmZF5LdpBsAEjWX8QYjSCa4FrkIYtbfXUJJJnFCYrOtt6TZ+IAiTjBQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.6.3.tgz", - "integrity": "sha512-KoXfJ42k8cqbkfshW7sSHcdfnv5agDdHCPA87ZBdmHP+zJstTJc0ttQaJ/x7zK6noAL76hOuTIJ6ZkQRS5dcyg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", "dev": true, "requires": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", "jest-get-type": "^29.6.3", - "jest-util": "^29.6.3", - "pretty-format": "^29.6.3" + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" } }, "jest-environment-node": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.6.4.tgz", - "integrity": "sha512-i7SbpH2dEIFGNmxGCpSc2w9cA4qVD+wfvg2ZnfQ7XVrKL0NA5uDVBIiGH8SR4F0dKEv/0qI5r+aDomDf04DpEQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dev": true, "requires": { - "@jest/environment": "^29.6.4", - "@jest/fake-timers": "^29.6.4", + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", - "jest-mock": "^29.6.3", - "jest-util": "^29.6.3" + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" } }, "jest-get-type": { @@ -7884,9 +7819,9 @@ "dev": true }, "jest-haste-map": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.6.4.tgz", - "integrity": "sha512-12Ad+VNTDHxKf7k+M65sviyynRoZYuL1/GTuhEVb8RYsNSNln71nANRb/faSyWvx0j+gHcivChXHIoMJrGYjog==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, "requires": { "@jest/types": "^29.6.3", @@ -7897,38 +7832,38 @@ "fsevents": "^2.3.2", "graceful-fs": "^4.2.9", "jest-regex-util": "^29.6.3", - "jest-util": "^29.6.3", - "jest-worker": "^29.6.4", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "walker": "^1.0.8" } }, "jest-leak-detector": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.6.3.tgz", - "integrity": "sha512-0kfbESIHXYdhAdpLsW7xdwmYhLf1BRu4AA118/OxFm0Ho1b2RcTmO4oF6aAMaxpxdxnJ3zve2rgwzNBD4Zbm7Q==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, "requires": { "jest-get-type": "^29.6.3", - "pretty-format": "^29.6.3" + "pretty-format": "^29.7.0" } }, "jest-matcher-utils": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.6.4.tgz", - "integrity": "sha512-KSzwyzGvK4HcfnserYqJHYi7sZVqdREJ9DMPAKVbS98JsIAvumihaNUbjrWw0St7p9IY7A9UskCW5MYlGmBQFQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^29.6.4", + "jest-diff": "^29.7.0", "jest-get-type": "^29.6.3", - "pretty-format": "^29.6.3" + "pretty-format": "^29.7.0" } }, "jest-message-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.6.3.tgz", - "integrity": "sha512-FtzaEEHzjDpQp51HX4UMkPZjy46ati4T5pEMyM6Ik48ztu4T9LQplZ6OsimHx7EuM9dfEh5HJa6D3trEftu3dA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", @@ -7937,20 +7872,20 @@ "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" } }, "jest-mock": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.6.3.tgz", - "integrity": "sha512-Z7Gs/mOyTSR4yPsaZ72a/MtuK6RnC3JYqWONe48oLaoEcYwEDxqvbXz85G4SJrm2Z5Ar9zp6MiHF4AlFlRM4Pg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", "dev": true, "requires": { "@jest/types": "^29.6.3", "@types/node": "*", - "jest-util": "^29.6.3" + "jest-util": "^29.7.0" } }, "jest-pnp-resolver": { @@ -7967,73 +7902,73 @@ "dev": true }, "jest-resolve": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.6.4.tgz", - "integrity": "sha512-fPRq+0vcxsuGlG0O3gyoqGTAxasagOxEuyoxHeyxaZbc9QNek0AmJWSkhjlMG+mTsj+8knc/mWb3fXlRNVih7Q==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, "requires": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.6.4", + "jest-haste-map": "^29.7.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.6.3", - "jest-validate": "^29.6.3", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", "resolve": "^1.20.0", "resolve.exports": "^2.0.0", "slash": "^3.0.0" } }, "jest-resolve-dependencies": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.4.tgz", - "integrity": "sha512-7+6eAmr1ZBF3vOAJVsfLj1QdqeXG+WYhidfLHBRZqGN24MFRIiKG20ItpLw2qRAsW/D2ZUUmCNf6irUr/v6KHA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dev": true, "requires": { "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.6.4" + "jest-snapshot": "^29.7.0" } }, "jest-runner": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.6.4.tgz", - "integrity": "sha512-SDaLrMmtVlQYDuG0iSPYLycG8P9jLI+fRm8AF/xPKhYDB2g6xDWjXBrR5M8gEWsK6KVFlebpZ4QsrxdyIX1Jaw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, "requires": { - "@jest/console": "^29.6.4", - "@jest/environment": "^29.6.4", - "@jest/test-result": "^29.6.4", - "@jest/transform": "^29.6.4", + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.13.1", "graceful-fs": "^4.2.9", - "jest-docblock": "^29.6.3", - "jest-environment-node": "^29.6.4", - "jest-haste-map": "^29.6.4", - "jest-leak-detector": "^29.6.3", - "jest-message-util": "^29.6.3", - "jest-resolve": "^29.6.4", - "jest-runtime": "^29.6.4", - "jest-util": "^29.6.3", - "jest-watcher": "^29.6.4", - "jest-worker": "^29.6.4", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" } }, "jest-runtime": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.6.4.tgz", - "integrity": "sha512-s/QxMBLvmwLdchKEjcLfwzP7h+jsHvNEtxGP5P+Fl1FMaJX2jMiIqe4rJw4tFprzCwuSvVUo9bn0uj4gNRXsbA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", "dev": true, "requires": { - "@jest/environment": "^29.6.4", - "@jest/fake-timers": "^29.6.4", - "@jest/globals": "^29.6.4", + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.6.4", - "@jest/transform": "^29.6.4", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", @@ -8041,21 +7976,21 @@ "collect-v8-coverage": "^1.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.6.4", - "jest-message-util": "^29.6.3", - "jest-mock": "^29.6.3", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.6.4", - "jest-snapshot": "^29.6.4", - "jest-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" } }, "jest-snapshot": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.6.4.tgz", - "integrity": "sha512-VC1N8ED7+4uboUKGIDsbvNAZb6LakgIPgAF4RSpF13dN6YaMokfRqO+BaqK4zIh6X3JffgwbzuGqDEjHm/MrvA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, "requires": { "@babel/core": "^7.11.6", @@ -8063,20 +7998,20 @@ "@babel/plugin-syntax-jsx": "^7.7.2", "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.6.4", - "@jest/transform": "^29.6.4", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", "@jest/types": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^29.6.4", + "expect": "^29.7.0", "graceful-fs": "^4.2.9", - "jest-diff": "^29.6.4", + "jest-diff": "^29.7.0", "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.6.4", - "jest-message-util": "^29.6.3", - "jest-util": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", "natural-compare": "^1.4.0", - "pretty-format": "^29.6.3", + "pretty-format": "^29.7.0", "semver": "^7.5.3" }, "dependencies": { @@ -8107,9 +8042,9 @@ } }, "jest-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz", - "integrity": "sha512-QUjna/xSy4B32fzcKTSz1w7YYzgiHrjjJjevdRf61HYk998R5vVMMNmrHESYZVDS5DSWs+1srPLPKxXPkeSDOA==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, "requires": { "@jest/types": "^29.6.3", @@ -8121,9 +8056,9 @@ } }, "jest-validate": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.6.3.tgz", - "integrity": "sha512-e7KWZcAIX+2W1o3cHfnqpGajdCs1jSM3DkXjGeLSNmCazv1EeI1ggTeK5wdZhF+7N+g44JI2Od3veojoaumlfg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, "requires": { "@jest/types": "^29.6.3", @@ -8131,7 +8066,7 @@ "chalk": "^4.0.0", "jest-get-type": "^29.6.3", "leven": "^3.1.0", - "pretty-format": "^29.6.3" + "pretty-format": "^29.7.0" }, "dependencies": { "camelcase": { @@ -8143,29 +8078,29 @@ } }, "jest-watcher": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.6.4.tgz", - "integrity": "sha512-oqUWvx6+On04ShsT00Ir9T4/FvBeEh2M9PTubgITPxDa739p4hoQweWPRGyYeaojgT0xTpZKF0Y/rSY1UgMxvQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dev": true, "requires": { - "@jest/test-result": "^29.6.4", + "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.13.1", - "jest-util": "^29.6.3", + "jest-util": "^29.7.0", "string-length": "^4.0.1" } }, "jest-worker": { - "version": "29.6.4", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.6.4.tgz", - "integrity": "sha512-6dpvFV4WjcWbDVGgHTWo/aupl8/LbBx2NSKfiwqf79xC/yeJjKHT1+StcKy/2KTmW16hE68ccKVOtXf+WZGz7Q==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, "requires": { "@types/node": "*", - "jest-util": "^29.6.3", + "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, @@ -8202,6 +8137,12 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -8226,6 +8167,15 @@ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, + "keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, "kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -8372,9 +8322,7 @@ } }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.2" }, "natural-compare": { "version": "1.4.0", @@ -8384,26 +8332,18 @@ }, "node-fetch": { "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "requires": { "whatwg-url": "^5.0.0" }, "dependencies": { "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "version": "0.0.3" }, "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "version": "3.0.1" }, "whatwg-url": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -8440,8 +8380,6 @@ }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" } @@ -8623,9 +8561,9 @@ "dev": true }, "pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "requires": { "@jest/schemas": "^29.6.3", @@ -8658,9 +8596,9 @@ "dev": true }, "pure-rand": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", - "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.3.tgz", + "integrity": "sha512-KddyFewCsO0j3+np81IQ+SweXLDnDQTs5s67BOnrYmYe/yNmUhttQyGsYzy8yUnoljGAQ9sl38YB4vH8ur7Y+w==", "dev": true }, "queue-microtask": { @@ -8682,9 +8620,9 @@ "dev": true }, "resolve": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", - "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "version": "1.22.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", + "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", "dev": true, "requires": { "is-core-module": "^2.13.0", @@ -8746,9 +8684,7 @@ } }, "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + "version": "6.3.1" }, "shebang-command": { "version": "2.0.0", @@ -8773,8 +8709,6 @@ }, "simple-git": { "version": "3.19.1", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.19.1.tgz", - "integrity": "sha512-Ck+rcjVaE1HotraRAS8u/+xgTvToTuoMkT9/l9lvuP5jftwnYUp6DwuJzsKErHgfyRk8IB8pqGHWEbM3tLgV1w==", "requires": { "@kwsites/file-exists": "^1.1.1", "@kwsites/promise-deferred": "^1.1.1", @@ -8934,9 +8868,9 @@ } }, "ts-api-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", - "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", "dev": true, "requires": {} }, @@ -8983,9 +8917,7 @@ } }, "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" + "version": "0.0.6" }, "type-check": { "version": "0.4.0", @@ -9015,9 +8947,7 @@ "dev": true }, "universal-user-agent": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" + "version": "6.0.0" }, "update-browserslist-db": { "version": "1.0.11", @@ -9039,9 +8969,7 @@ } }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "version": "3.4.0" }, "v8-to-istanbul": { "version": "9.1.0", @@ -9092,9 +9020,7 @@ } }, "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "version": "1.0.2" }, "write-file-atomic": { "version": "4.0.2", diff --git a/action/src/utils.ts b/action/src/utils.ts index 90652fc16..da3fbe2c1 100644 --- a/action/src/utils.ts +++ b/action/src/utils.ts @@ -4,8 +4,8 @@ import { context as githubContext } from '@actions/github'; import { downloadTool, find, cacheFile } from '@actions/tool-cache'; import { chmodSync } from 'fs'; import { platform, arch } from 'os'; -import { join } from 'path'; -import {BranchSummary, SimpleGit, simpleGit} from 'simple-git'; +import { normalize, join } from 'path'; +import { BranchSummary, SimpleGit, simpleGit } from 'simple-git'; export class Utils { private static readonly LATEST_RELEASE_VERSION: string = '[RELEASE]'; @@ -68,7 +68,7 @@ export class Utils { */ public static async execScanPullRequest() { if (!process.env.JF_GIT_BASE_BRANCH) { - core.exportVariable('JF_GIT_BASE_BRANCH', githubContext.ref) + core.exportVariable('JF_GIT_BASE_BRANCH', githubContext.ref); } let res: number = await exec(Utils.getExecutableName(), ['scan-pull-request']); if (res !== core.ExitCode.Success) { @@ -121,7 +121,8 @@ export class Utils { private static async cacheAndAddPath(downloadDir: string, version: string, fileName: string) { let cliDir: string = await cacheFile(downloadDir, fileName, Utils.TOOL_NAME, version); if (!Utils.isWindows()) { - chmodSync(join(cliDir, fileName), 0o555); + let filePath: string = normalize(join(cliDir, fileName)); + chmodSync(filePath, 0o555); } core.addPath(cliDir); } diff --git a/buildscripts/build.sh b/buildscripts/build.sh index 8d4f68052..0e8a45945 100755 --- a/buildscripts/build.sh +++ b/buildscripts/build.sh @@ -7,4 +7,4 @@ if [ $# -eq 0 ] exe_name="$1" fi -CGO_ENABLED=0 go build -o $exe_name -ldflags '-w -extldflags "-static"' \ No newline at end of file +CGO_ENABLED=0 go build -o "$exe_name" -ldflags '-w -extldflags "-static"' \ No newline at end of file diff --git a/buildscripts/getFrogbot.sh b/buildscripts/getFrogbot.sh index fc690d5a7..d08b4e8a8 100644 --- a/buildscripts/getFrogbot.sh +++ b/buildscripts/getFrogbot.sh @@ -62,7 +62,7 @@ setLinuxProperties() { ;; *) echo "Unknown machine type: $MACHINE_TYPE" - exit -1 + exit 1 ;; esac URL="${PLATFORM_URL}/artifactory/${REMOTE_PATH}frogbot/v2/${VERSION}/frogbot-${FROGBOT_OS}-${ARCH}/frogbot" @@ -70,9 +70,9 @@ setLinuxProperties() { } setFrogbotDownloadProperties() { - if $(echo "${OSTYPE}" | grep -q msys); then + if echo "${OSTYPE}" | grep -q msys; then setWindowsProperties - elif $(echo "${OSTYPE}" | grep -q darwin); then + elif echo "${OSTYPE}" | grep -q darwin; then setMacProperties else setLinuxProperties diff --git a/docs/install-azure-pipelines.md b/docs/install-azure-pipelines.md index 7e7833dcb..f867eee21 100644 --- a/docs/install-azure-pipelines.md +++ b/docs/install-azure-pipelines.md @@ -313,6 +313,12 @@ jobs: # detected during pull request scanning. The notification is also sent to the email set # in the committer git profile regardless of whether this variable is set or not. # JF_EMAIL_RECEIVERS: "" + + # [Optional] + # Set the list of allowed licenses + # The full list of licenses can be found in: + # https://github.com/jfrog/frogbot/blob/master/docs/licenses.md + # JF_ALLOWED_LICENSES: "MIT, Apache-2.0" inputs: script: | diff --git a/docs/install-gitlab.md b/docs/install-gitlab.md index 43581a40f..18419a15f 100644 --- a/docs/install-gitlab.md +++ b/docs/install-gitlab.md @@ -168,6 +168,12 @@ frogbot-scan: # in the committer git profile regardless of whether this variable is set or not. # JF_EMAIL_RECEIVERS: "" + # [Optional] + # Set the list of allowed licenses + # The full list of licenses can be found in: + # https://github.com/jfrog/frogbot/blob/master/docs/licenses.md + # JF_ALLOWED_LICENSES: "MIT, Apache-2.0" + script: # For Linux / MacOS runner: - | diff --git a/docs/licenses.md b/docs/licenses.md new file mode 100644 index 000000000..115e48c4e --- /dev/null +++ b/docs/licenses.md @@ -0,0 +1,548 @@ +## ⚖️ Allowed Licenses + +- 0BSD +- AAL +- Abstyles +- AdaCore-doc +- Adobe-2006 +- Adobe-Glyph +- ADSL +- AFL-1.1 +- AFL-1.2 +- AFL-2.0 +- AFL-2.1 +- AFL-3.0 +- Afmparse +- AGPL-1.0-only +- AGPL-1.0-or-later +- AGPL-3.0-only +- AGPL-3.0-or-later +- Aladdin +- AMDPLPA +- AML +- AMPAS +- ANTLR-PD +- ANTLR-PD-fallback +- Apache-1.0 +- Apache-1.1 +- Apache-2.0 +- APAFML +- APL-1.0 +- App-s2p +- APSL-1.0 +- APSL-1.1 +- APSL-1.2 +- APSL-2.0 +- Arphic-1999 +- Artistic-1.0 +- Artistic-1.0-cl8 +- Artistic-1.0-Perl +- Artistic-2.0 +- ASWF-Digital-Assets-1.0 +- ASWF-Digital-Assets-1.1 +- Baekmuk +- Bahyph +- Barr +- Beerware +- Bitstream-Charter +- Bitstream-Vera +- BitTorrent-1.0 +- BitTorrent-1.1 +- blessing +- BlueOak-1.0.0 +- Boehm-GC +- Borceux +- Brian-Gladman-3-Clause +- BSD-1-Clause +- BSD-2-Clause +- BSD-2-Clause-Patent +- BSD-2-Clause-Views +- BSD-3-Clause +- BSD-3-Clause-Attribution +- BSD-3-Clause-Clear +- BSD-3-Clause-LBNL +- BSD-3-Clause-Modification +- BSD-3-Clause-No-Military-License +- BSD-3-Clause-No-Nuclear-License +- BSD-3-Clause-No-Nuclear-License-2014 +- BSD-3-Clause-No-Nuclear-Warranty +- BSD-3-Clause-Open-MPI +- BSD-3-Clause-Sun +- BSD-4-Clause +- BSD-4-Clause-Shortened +- BSD-4-Clause-UC +- BSD-4.3RENO +- BSD-4.3TAHOE +- BSD-Advertising-Acknowledgement +- BSD-Attribution-HPND-disclaimer +- BSD-Protection +- BSD-Source-Code +- BSD-Systemics +- BSL-1.0 +- BUSL-1.1 +- bzip2-1.0.6 +- C-UDA-1.0 +- CAL-1.0 +- CAL-1.0-Combined-Work-Exception +- Caldera +- CATOSL-1.1 +- CC-BY-1.0 +- CC-BY-2.0 +- CC-BY-2.5 +- CC-BY-2.5-AU +- CC-BY-3.0 +- CC-BY-3.0-AT +- CC-BY-3.0-DE +- CC-BY-3.0-IGO +- CC-BY-3.0-NL +- CC-BY-3.0-US +- CC-BY-4.0 +- CC-BY-NC-1.0 +- CC-BY-NC-2.0 +- CC-BY-NC-2.5 +- CC-BY-NC-3.0 +- CC-BY-NC-3.0-DE +- CC-BY-NC-4.0 +- CC-BY-NC-ND-1.0 +- CC-BY-NC-ND-2.0 +- CC-BY-NC-ND-2.5 +- CC-BY-NC-ND-3.0 +- CC-BY-NC-ND-3.0-DE +- CC-BY-NC-ND-3.0-IGO +- CC-BY-NC-ND-4.0 +- CC-BY-NC-SA-1.0 +- CC-BY-NC-SA-2.0 +- CC-BY-NC-SA-2.0-DE +- CC-BY-NC-SA-2.0-FR +- CC-BY-NC-SA-2.0-UK +- CC-BY-NC-SA-2.5 +- CC-BY-NC-SA-3.0 +- CC-BY-NC-SA-3.0-DE +- CC-BY-NC-SA-3.0-IGO +- CC-BY-NC-SA-4.0 +- CC-BY-ND-1.0 +- CC-BY-ND-2.0 +- CC-BY-ND-2.5 +- CC-BY-ND-3.0 +- CC-BY-ND-3.0-DE +- CC-BY-ND-4.0 +- CC-BY-SA-1.0 +- CC-BY-SA-2.0 +- CC-BY-SA-2.0-UK +- CC-BY-SA-2.1-JP +- CC-BY-SA-2.5 +- CC-BY-SA-3.0 +- CC-BY-SA-3.0-AT +- CC-BY-SA-3.0-DE +- CC-BY-SA-3.0-IGO +- CC-BY-SA-4.0 +- CC-PDDC +- CC0-1.0 +- CDDL-1.0 +- CDDL-1.1 +- CDL-1.0 +- CDLA-Permissive-1.0 +- CDLA-Permissive-2.0 +- CDLA-Sharing-1.0 +- CECILL-1.0 +- CECILL-1.1 +- CECILL-2.0 +- CECILL-2.1 +- CECILL-B +- CECILL-C +- CERN-OHL-1.1 +- CERN-OHL-1.2 +- CERN-OHL-P-2.0 +- CERN-OHL-S-2.0 +- CERN-OHL-W-2.0 +- CFITSIO +- check-cvs +- checkmk +- ClArtistic +- Clips +- CMU-Mach +- CNRI-Jython +- CNRI-Python +- CNRI-Python-GPL-Compatible +- COIL-1.0 +- Community-Spec-1.0 +- Condor-1.1 +- copyleft-next-0.3.0 +- copyleft-next-0.3.1 +- Cornell-Lossless-JPEG +- CPAL-1.0 +- CPL-1.0 +- CPOL-1.02 +- Crossword +- CrystalStacker +- CUA-OPL-1.0 +- Cube +- curl +- D-FSL-1.0 +- diffmark +- DL-DE-BY-2.0 +- DL-DE-ZERO-2.0 +- DOC +- Dotseqn +- DRL-1.0 +- DSDP +- dtoa +- dvipdfm +- ECL-1.0 +- ECL-2.0 +- EFL-1.0 +- EFL-2.0 +- eGenix +- Elastic-2.0 +- Entessa +- EPICS +- EPL-1.0 +- EPL-2.0 +- ErlPL-1.1 +- etalab-2.0 +- EUDatagrid +- EUPL-1.0 +- EUPL-1.1 +- EUPL-1.2 +- Eurosym +- Fair +- FBM +- FDK-AAC +- Ferguson-Twofish +- Frameworx-1.0 +- FreeBSD-DOC +- FreeImage +- FSFAP +- FSFUL +- FSFULLR +- FSFULLRWD +- FTL +- GD +- GFDL-1.1-invariants-only +- GFDL-1.1-invariants-or-later +- GFDL-1.1-no-invariants-only +- GFDL-1.1-no-invariants-or-later +- GFDL-1.1-only +- GFDL-1.1-or-later +- GFDL-1.2-invariants-only +- GFDL-1.2-invariants-or-later +- GFDL-1.2-no-invariants-only +- GFDL-1.2-no-invariants-or-later +- GFDL-1.2-only +- GFDL-1.2-or-later +- GFDL-1.3-invariants-only +- GFDL-1.3-invariants-or-later +- GFDL-1.3-no-invariants-only +- GFDL-1.3-no-invariants-or-later +- GFDL-1.3-only +- GFDL-1.3-or-later +- Giftware +- GL2PS +- Glide +- Glulxe +- GLWTPL +- GNU-compiler-exception +- gnuplot +- GPL-1.0-only +- GPL-1.0-or-later +- GPL-2.0-only +- GPL-2.0-or-later +- GPL-3.0-only +- GPL-3.0-or-later +- Graphics-Gems +- gSOAP-1.3b +- HaskellReport +- Hippocratic-2.1 +- HP-1986 +- HP-1989 +- HPND +- HPND-export-US +- HPND-Markus-Kuhn +- HPND-sell-variant +- HPND-sell-variant-MIT-disclaimer +- HTMLTIDY +- IBM-pibs +- ICU +- IEC-Code-Components-EULA +- IJG +- IJG-short +- ImageMagick +- iMatix +- Imlib2 +- Info-ZIP +- Inner-Net-2.0 +- Intel +- Intel-ACPI +- Interbase-1.0 +- IPA +- IPL-1.0 +- ISC +- Jam +- JasPer-2.0 +- JPL-image +- JPNIC +- JSON +- Kazlib +- Knuth-CTAN +- LAL-1.2 +- LAL-1.3 +- Latex2e +- Latex2e-translated-notice +- Leptonica +- LGPL-2.0-only +- LGPL-2.0-or-later +- LGPL-2.1-only +- LGPL-2.1-or-later +- LGPL-3.0-only +- LGPL-3.0-or-later +- LGPLLR +- Libpng +- libpng-2.0 +- libselinux-1.0 +- libtiff +- libutil-David-Nugent +- LiLiQ-P-1.1 +- LiLiQ-R-1.1 +- LiLiQ-Rplus-1.1 +- Linux-man-pages-1-para +- Linux-man-pages-copyleft +- Linux-man-pages-copyleft-2-para +- Linux-man-pages-copyleft-var +- Linux-OpenIB +- LOOP +- LPL-1.0 +- LPL-1.02 +- LPPL-1.0 +- LPPL-1.1 +- LPPL-1.2 +- LPPL-1.3a +- LPPL-1.3c +- LZMA-SDK-9.11-to-9.20 +- LZMA-SDK-9.22 +- MakeIndex +- Martin-Birgmeier +- metamail +- Minpack +- MirOS +- MIT +- MIT-0 +- MIT-advertising +- MIT-CMU +- MIT-enna +- MIT-feh +- MIT-Festival +- MIT-Modern-Variant +- MIT-open-group +- MIT-testregex +- MIT-Wu +- MITNFA +- MMIXware +- Motosoto +- MPEG-SSG +- mpi-permissive +- mpich2 +- MPL-1.0 +- MPL-1.1 +- MPL-2.0 +- MPL-2.0-no-copyleft-exception +- mplus +- MS-LPL +- MS-PL +- MS-RL +- MTLL +- MulanPSL-1.0 +- MulanPSL-2.0 +- Multics +- Mup +- NAIST-2003 +- NASA-1.3 +- Naumen +- NBPL-1.0 +- NCGL-UK-2.0 +- NCSA +- Net-SNMP +- NetCDF +- Newsletr +- NGPL +- NICTA-1.0 +- NIST-PD +- NIST-PD-fallback +- NIST-Software +- NLOD-1.0 +- NLOD-2.0 +- NLPL +- Nokia +- NOSL +- Noweb +- NPL-1.0 +- NPL-1.1 +- NPOSL-3.0 +- NRL +- NTP +- NTP-0 +- O-UDA-1.0 +- OCCT-PL +- OCLC-2.0 +- ODbL-1.0 +- ODC-By-1.0 +- OFFIS +- OFL-1.0 +- OFL-1.0-no-RFN +- OFL-1.0-RFN +- OFL-1.1 +- OFL-1.1-no-RFN +- OFL-1.1-RFN +- OGC-1.0 +- OGDL-Taiwan-1.0 +- OGL-Canada-2.0 +- OGL-UK-1.0 +- OGL-UK-2.0 +- OGL-UK-3.0 +- OGTSL +- OLDAP-1.1 +- OLDAP-1.2 +- OLDAP-1.3 +- OLDAP-1.4 +- OLDAP-2.0 +- OLDAP-2.0.1 +- OLDAP-2.1 +- OLDAP-2.2 +- OLDAP-2.2.1 +- OLDAP-2.2.2 +- OLDAP-2.3 +- OLDAP-2.4 +- OLDAP-2.5 +- OLDAP-2.6 +- OLDAP-2.7 +- OLDAP-2.8 +- OLFL-1.3 +- OML +- OpenPBS-2.3 +- OpenSSL +- OPL-1.0 +- OPL-UK-3.0 +- OPUBL-1.0 +- OSET-PL-2.1 +- OSL-1.0 +- OSL-1.1 +- OSL-2.0 +- OSL-2.1 +- OSL-3.0 +- Parity-6.0.0 +- Parity-7.0.0 +- PDDL-1.0 +- PHP-3.0 +- PHP-3.01 +- Plexus +- pnmstitch +- PolyForm-Noncommercial-1.0.0 +- PolyForm-Small-Business-1.0.0 +- PostgreSQL +- PSF-2.0 +- psfrag +- psutils +- Python-2.0 +- Python-2.0.1 +- Qhull +- QPL-1.0 +- QPL-1.0-INRIA-2004 +- Rdisc +- RHeCos-1.1 +- RPL-1.1 +- RPL-1.5 +- RPSL-1.0 +- RSA-MD +- RSCPL +- Ruby +- SANE-exception +- SAX-PD +- Saxpath +- SCEA +- SchemeReport +- Sendmail +- Sendmail-8.23 +- SGI-B-1.0 +- SGI-B-1.1 +- SGI-B-2.0 +- SGP4 +- SHL-0.5 +- SHL-0.51 +- SimPL-2.0 +- SISSL +- SISSL-1.2 +- SL +- Sleepycat +- SMLNJ +- SMPPL +- SNIA +- snprintf +- Soundex +- Spencer-86 +- Spencer-94 +- Spencer-99 +- SPL-1.0 +- SSH-OpenSSH +- SSH-short +- SSPL-1.0 +- stunnel-exception +- SugarCRM-1.1.3 +- SunPro +- SWL +- Symlinks +- TAPR-OHL-1.0 +- TCL +- TCP-wrappers +- TermReadKey +- Texinfo-exception +- TMate +- TORQUE-1.1 +- TOSL +- TPDL +- TPL-1.0 +- TTWL +- TTYP0 +- TU-Berlin-1.0 +- TU-Berlin-2.0 +- UCAR +- UCL-1.0 +- Unicode-DFS-2015 +- Unicode-DFS-2016 +- Unicode-TOU +- UnixCrypt +- Unlicense +- UPL-1.0 +- URT-RLE +- Vim +- VOSTROM +- VSL-1.0 +- W3C +- W3C-19980720 +- W3C-20150513 +- w3m +- Watcom-1.0 +- Widget-Workshop +- Wsuipa +- WTFPL +- X11 +- X11-distribute-modifications-variant +- Xdebug-1.03 +- Xerox +- Xfig +- XFree86-1.1 +- xinetd +- xlock +- Xnet +- xpp +- XSkat +- YPL-1.0 +- YPL-1.1 +- Zed +- Zeeff +- Zend-2.0 +- Zimbra-1.3 +- Zimbra-1.4 +- Zlib +- zlib-acknowledgement +- ZPL-1.1 +- ZPL-2.0 +- ZPL-2.1 \ No newline at end of file diff --git a/docs/templates/.frogbot/frogbot-config.yml b/docs/templates/.frogbot/frogbot-config.yml index 9dfffd8c5..9b4c22d8c 100644 --- a/docs/templates/.frogbot/frogbot-config.yml +++ b/docs/templates/.frogbot/frogbot-config.yml @@ -52,6 +52,14 @@ # Handle vulnerabilities with fix versions only # fixableOnly: true + # [Optional] + # Set the list of allowed licenses + # The full list of licenses can be found in: + # https://github.com/jfrog/frogbot/blob/master/docs/licenses.md + # allowedLicenses: + # - MIT + # - Apache-2.0 + # [Optional] # Set the minimum severity for vulnerabilities that should be fixed and commented on in pull requests # The following values are accepted: Low, Medium, High or Critical @@ -61,7 +69,7 @@ # List of email addresses to receive emails about secrets that has been detected in a pull request scan. # Applies only to servers that are entitled to JFrog Advanced Security. # emailReceivers: - # - user@company.com + # - user@company.com # List of subprojects / project dirs inside the Git repository projects: diff --git a/docs/templates/github-actions/frogbot-scan-pull-request.yml b/docs/templates/github-actions/frogbot-scan-pull-request.yml index b7218c77e..c69d2dd72 100644 --- a/docs/templates/github-actions/frogbot-scan-pull-request.yml +++ b/docs/templates/github-actions/frogbot-scan-pull-request.yml @@ -124,3 +124,9 @@ jobs: # detected during pull request scanning. The notification is also sent to the email set # in the committer git profile regardless of whether this variable is set or not. # JF_EMAIL_RECEIVERS: "" + + # [Optional] + # Set the list of allowed licenses + # The full list of licenses can be found in: + # https://github.com/jfrog/frogbot/blob/master/docs/licenses.md + # JF_ALLOWED_LICENSES: "MIT, Apache-2.0" diff --git a/docs/templates/jfrog-pipelines/pipelines-dotnet.yml b/docs/templates/jfrog-pipelines/pipelines-dotnet.yml index 014f94fac..7bd5e1d5c 100644 --- a/docs/templates/jfrog-pipelines/pipelines-dotnet.yml +++ b/docs/templates/jfrog-pipelines/pipelines-dotnet.yml @@ -179,6 +179,12 @@ pipelines: # in the committer git profile regardless of whether this variable is set or not. # JF_EMAIL_RECEIVERS: "" + # [Optional] + # Set the list of allowed licenses + # The full list of licenses can be found in: + # https://github.com/jfrog/frogbot/blob/master/docs/licenses.md + # JF_ALLOWED_LICENSES: "MIT, Apache-2.0" + execution: onExecute: - cd $res_frogbotGitRepo_resourcePath diff --git a/docs/templates/jfrog-pipelines/pipelines-go.yml b/docs/templates/jfrog-pipelines/pipelines-go.yml index db7177200..0a7161786 100644 --- a/docs/templates/jfrog-pipelines/pipelines-go.yml +++ b/docs/templates/jfrog-pipelines/pipelines-go.yml @@ -180,6 +180,12 @@ pipelines: # in the committer git profile regardless of whether this variable is set or not. # JF_EMAIL_RECEIVERS: "" + # [Optional] + # Set the list of allowed licenses + # The full list of licenses can be found in: + # https://github.com/jfrog/frogbot/blob/master/docs/licenses.md + # JF_ALLOWED_LICENSES: "MIT, Apache-2.0" + execution: onExecute: - cd $res_frogbotGitRepo_resourcePath diff --git a/docs/templates/jfrog-pipelines/pipelines-gradle.yml b/docs/templates/jfrog-pipelines/pipelines-gradle.yml index 654f99388..f8bde3740 100644 --- a/docs/templates/jfrog-pipelines/pipelines-gradle.yml +++ b/docs/templates/jfrog-pipelines/pipelines-gradle.yml @@ -184,6 +184,12 @@ pipelines: # in the committer git profile regardless of whether this variable is set or not. # JF_EMAIL_RECEIVERS: "" + # [Optional] + # Set the list of allowed licenses + # The full list of licenses can be found in: + # https://github.com/jfrog/frogbot/blob/master/docs/licenses.md + # JF_ALLOWED_LICENSES: "MIT, Apache-2.0" + execution: onExecute: - cd $res_frogbotGitRepo_resourcePath diff --git a/docs/templates/jfrog-pipelines/pipelines-maven.yml b/docs/templates/jfrog-pipelines/pipelines-maven.yml index 091ee29c4..e9b5e2589 100644 --- a/docs/templates/jfrog-pipelines/pipelines-maven.yml +++ b/docs/templates/jfrog-pipelines/pipelines-maven.yml @@ -172,6 +172,12 @@ pipelines: # in the committer git profile regardless of whether this variable is set or not. # JF_EMAIL_RECEIVERS: "" + # [Optional] + # Set the list of allowed licenses + # The full list of licenses can be found in: + # https://github.com/jfrog/frogbot/blob/master/docs/licenses.md + # JF_ALLOWED_LICENSES: "MIT, Apache-2.0" + execution: onExecute: - cd $res_frogbotGitRepo_resourcePath diff --git a/docs/templates/jfrog-pipelines/pipelines-npm.yml b/docs/templates/jfrog-pipelines/pipelines-npm.yml index bbaa1cd56..8b61964fa 100644 --- a/docs/templates/jfrog-pipelines/pipelines-npm.yml +++ b/docs/templates/jfrog-pipelines/pipelines-npm.yml @@ -195,6 +195,12 @@ pipelines: # in the committer git profile regardless of whether this variable is set or not. # JF_EMAIL_RECEIVERS: "" + # [Optional] + # Set the list of allowed licenses + # The full list of licenses can be found in: + # https://github.com/jfrog/frogbot/blob/master/docs/licenses.md + # JF_ALLOWED_LICENSES: "MIT, Apache-2.0" + execution: onExecute: - cd $res_frogbotGitRepo_resourcePath diff --git a/docs/templates/jfrog-pipelines/pipelines-pip.yml b/docs/templates/jfrog-pipelines/pipelines-pip.yml index 9ecc538c8..f141006cd 100644 --- a/docs/templates/jfrog-pipelines/pipelines-pip.yml +++ b/docs/templates/jfrog-pipelines/pipelines-pip.yml @@ -183,6 +183,12 @@ pipelines: # in the committer git profile regardless of whether this variable is set or not. # JF_EMAIL_RECEIVERS: "" + # [Optional] + # Set the list of allowed licenses + # The full list of licenses can be found in: + # https://github.com/jfrog/frogbot/blob/master/docs/licenses.md + # JF_ALLOWED_LICENSES: "MIT, Apache-2.0" + execution: onExecute: - cd $res_frogbotGitRepo_resourcePath diff --git a/docs/templates/jfrog-pipelines/pipelines-pipenv.yml b/docs/templates/jfrog-pipelines/pipelines-pipenv.yml index f33db9667..51a515b6b 100644 --- a/docs/templates/jfrog-pipelines/pipelines-pipenv.yml +++ b/docs/templates/jfrog-pipelines/pipelines-pipenv.yml @@ -176,6 +176,12 @@ pipelines: # in the committer git profile regardless of whether this variable is set or not. # JF_EMAIL_RECEIVERS: "" + # [Optional] + # Set the list of allowed licenses + # The full list of licenses can be found in: + # https://github.com/jfrog/frogbot/blob/master/docs/licenses.md + # JF_ALLOWED_LICENSES: "MIT, Apache-2.0" + execution: onExecute: - cd $res_frogbotGitRepo_resourcePath diff --git a/docs/templates/jfrog-pipelines/pipelines-poetry.yml b/docs/templates/jfrog-pipelines/pipelines-poetry.yml index e66a7552f..616f5067e 100644 --- a/docs/templates/jfrog-pipelines/pipelines-poetry.yml +++ b/docs/templates/jfrog-pipelines/pipelines-poetry.yml @@ -176,6 +176,12 @@ pipelines: # in the committer git profile regardless of whether this variable is set or not. # JF_EMAIL_RECEIVERS: "" + # [Optional] + # Set the list of allowed licenses + # The full list of licenses can be found in: + # https://github.com/jfrog/frogbot/blob/master/docs/licenses.md + # JF_ALLOWED_LICENSES: "MIT, Apache-2.0" + execution: onExecute: - cd $res_frogbotGitRepo_resourcePath diff --git a/docs/templates/jfrog-pipelines/pipelines-yarn2.yml b/docs/templates/jfrog-pipelines/pipelines-yarn2.yml index a114b175b..96e5f5eed 100644 --- a/docs/templates/jfrog-pipelines/pipelines-yarn2.yml +++ b/docs/templates/jfrog-pipelines/pipelines-yarn2.yml @@ -179,6 +179,12 @@ pipelines: # in the committer git profile regardless of whether this variable is set or not. # JF_EMAIL_RECEIVERS: "" + # [Optional] + # Set the list of allowed licenses + # The full list of licenses can be found in: + # https://github.com/jfrog/frogbot/blob/master/docs/licenses.md + # JF_ALLOWED_LICENSES: "MIT, Apache-2.0" + execution: onExecute: - cd $res_frogbotGitRepo_resourcePath diff --git a/go.mod b/go.mod index a6135f2bf..4889485a5 100644 --- a/go.mod +++ b/go.mod @@ -7,12 +7,12 @@ require ( github.com/golang/mock v1.6.0 github.com/google/go-github/v45 v45.2.0 github.com/jfrog/build-info-go v1.9.10 - github.com/jfrog/froggit-go v1.14.1 + github.com/jfrog/froggit-go v1.14.2 github.com/jfrog/gofrog v1.3.0 - github.com/jfrog/jfrog-cli-core/v2 v2.43.0 - github.com/jfrog/jfrog-client-go v1.32.2 + github.com/jfrog/jfrog-cli-core/v2 v2.43.3 + github.com/jfrog/jfrog-client-go v1.32.3 github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible - github.com/owenrumney/go-sarif/v2 v2.2.0 + github.com/owenrumney/go-sarif/v2 v2.2.2 github.com/stretchr/testify v1.8.4 github.com/urfave/cli/v2 v2.25.7 github.com/xeipuuv/gojsonschema v1.2.0 @@ -29,7 +29,7 @@ require ( github.com/VividCortex/ewma v1.2.0 // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect github.com/acomagu/bufpipe v1.0.4 // indirect - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/andybalholm/brotli v1.0.4 // indirect github.com/buger/jsonparser v1.1.1 // indirect github.com/c-bata/go-prompt v0.2.5 // indirect github.com/chzyer/readline v1.5.1 // indirect @@ -115,5 +115,3 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) - -//replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 dev diff --git a/go.sum b/go.sum index df23aba65..5b06ad523 100644 --- a/go.sum +++ b/go.sum @@ -623,9 +623,8 @@ github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= @@ -880,14 +879,14 @@ github.com/jedib0t/go-pretty/v6 v6.4.7 h1:lwiTJr1DEkAgzljsUsORmWsVn5MQjt1BPJdPCt github.com/jedib0t/go-pretty/v6 v6.4.7/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs= github.com/jfrog/build-info-go v1.9.10 h1:uXnDLVxpqxoAMpXcki00QaBB+M2BoGMMpHODPkmmYOY= github.com/jfrog/build-info-go v1.9.10/go.mod h1:ujJ8XQZMdT2tMkLSMJNyDd1pCY+duwHdjV+9or9FLIg= -github.com/jfrog/froggit-go v1.14.1 h1:cmQUHvmoTDnEihh3IyPgGgjkUsIYiRo9M1YpDfPHfr8= -github.com/jfrog/froggit-go v1.14.1/go.mod h1:0jRAaZZusaFFnITosmx6CA60SKryuoaCasJyUrP/c1s= +github.com/jfrog/froggit-go v1.14.2 h1:55x1anQtaiARlSBMVT59aFU6Mmx90tpcvvAuuPsZm9c= +github.com/jfrog/froggit-go v1.14.2/go.mod h1:0jRAaZZusaFFnITosmx6CA60SKryuoaCasJyUrP/c1s= github.com/jfrog/gofrog v1.3.0 h1:o4zgsBZE4QyDbz2M7D4K6fXPTBJht+8lE87mS9bw7Gk= github.com/jfrog/gofrog v1.3.0/go.mod h1:IFMc+V/yf7rA5WZ74CSbXe+Lgf0iApEQLxRZVzKRUR0= -github.com/jfrog/jfrog-cli-core/v2 v2.43.0 h1:euo1CjZcpMdWkFUQ3zffRPfCR1zXhLD6TE/lfexV99o= -github.com/jfrog/jfrog-cli-core/v2 v2.43.0/go.mod h1:NWqT0ZnAvEdjaXGp64POvRV35TJ2R/c0W45UmrXQonk= -github.com/jfrog/jfrog-client-go v1.32.2 h1:t0ceWCtFri+xsa0D2ESqD/itcovlxBXCky1A1MJ4P2I= -github.com/jfrog/jfrog-client-go v1.32.2/go.mod h1:UewnwkIf/77HzBgwCPzOHZCK6V/Nw5/JwdzN/tRb4aU= +github.com/jfrog/jfrog-cli-core/v2 v2.43.3 h1:aZN+ZP2vIBBw2+U9F/iQ4Q2USmfXcxB8yN755azvjQo= +github.com/jfrog/jfrog-cli-core/v2 v2.43.3/go.mod h1:DKTOX9TsPkyI68GM4XdDTD7XDr+tOBqeK70DZZmu+4Q= +github.com/jfrog/jfrog-client-go v1.32.3 h1:B2M8Gu8EMrokbHWPPDgN1b7YRWwf0oe746epvQASK6c= +github.com/jfrog/jfrog-client-go v1.32.3/go.mod h1:UewnwkIf/77HzBgwCPzOHZCK6V/Nw5/JwdzN/tRb4aU= github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA= github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -964,8 +963,8 @@ github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7 github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U= -github.com/owenrumney/go-sarif/v2 v2.2.0 h1:1DmZaijK0HBZCR1fgcDSGa7VzYkU9NDmbZ7qC2QfUjE= -github.com/owenrumney/go-sarif/v2 v2.2.0/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w= +github.com/owenrumney/go-sarif/v2 v2.2.2 h1:x2acaiiAW9hu+78wbEYBRGLk5nRtHmkv7HeUsKvblwc= +github.com/owenrumney/go-sarif/v2 v2.2.2/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= diff --git a/packagehandlers/commonpackagehandler.go b/packagehandlers/commonpackagehandler.go index 7d9129616..3be5ea027 100644 --- a/packagehandlers/commonpackagehandler.go +++ b/packagehandlers/commonpackagehandler.go @@ -49,7 +49,7 @@ func (cph *CommonPackageHandler) UpdateDependency(vulnDetails *utils.Vulnerabili versionOperator := vulnDetails.Technology.GetPackageVersionOperator() fixedPackageArgs := getFixedPackage(impactedPackage, versionOperator, vulnDetails.SuggestedFixedVersion) commandArgs = append(commandArgs, fixedPackageArgs...) - return runPackageMangerCommand(vulnDetails.Technology.GetExecCommandName(), vulnDetails.Technology.ToString(), commandArgs) + return runPackageMangerCommand(vulnDetails.Technology.GetExecCommandName(), vulnDetails.Technology.String(), commandArgs) } func runPackageMangerCommand(commandName string, techName string, commandArgs []string) error { diff --git a/packagehandlers/mavenpackagehandler.go b/packagehandlers/mavenpackagehandler.go index 09006d0e6..66e8854dc 100644 --- a/packagehandlers/mavenpackagehandler.go +++ b/packagehandlers/mavenpackagehandler.go @@ -18,6 +18,7 @@ import ( "os" "os/exec" "path" + "path/filepath" "strings" ) @@ -91,7 +92,7 @@ func (mp *mavenPlugin) collectMavenPlugins() []gavCoordinate { // fillDependenciesMap collects direct dependencies from the pomPath pom.xml file. // If the version of a dependency is set in another property section, it is added as its value in the map. func (mph *MavenPackageHandler) fillDependenciesMap(pomPath string) error { - contentBytes, err := os.ReadFile(pomPath) // #nosec G304 + contentBytes, err := os.ReadFile(filepath.Clean(pomPath)) if err != nil { return errors.New("couldn't read pom.xml file: " + err.Error()) } @@ -126,10 +127,10 @@ func (mph *MavenPackageHandler) fillDependenciesMap(pomPath string) error { func getMavenDependencies(pomXmlContent []byte) (result []gavCoordinate, err error) { var dependencies mavenDependency if err = xml.Unmarshal(pomXmlContent, &dependencies); err != nil { - return result, err + return } result = append(result, dependencies.collectMavenDependencies(false)...) - return result, err + return } type pomPath struct { @@ -201,14 +202,7 @@ func (mph *MavenPackageHandler) installMavenGavReader() (err error) { return fmt.Errorf("failed to create a temp %s file: \n%s", mavenGavReader, err.Error()) } defer func() { - closeError := mavenGavReaderFile.Close() - deleteError := os.Remove(mavenGavReaderFile.Name()) - if err == nil { - err = closeError - if err == nil { - err = deleteError - } - } + err = errors.Join(err, mavenGavReaderFile.Close(), os.Remove(mavenGavReaderFile.Name())) }() gavReaderFolder := path.Dir(mavenGavReaderFile.Name()) currentWd, err := os.Getwd() @@ -216,23 +210,19 @@ func (mph *MavenPackageHandler) installMavenGavReader() (err error) { return } if err = os.Chdir(gavReaderFolder); err != nil { - return err + return fmt.Errorf("failed to change dir to the maven gav reader temp dir:\n%w", err) } defer func() { - e := os.Chdir(currentWd) - if err == nil { - err = e - } + err = errors.Join(err, os.Chdir(currentWd)) }() if _, err = mavenGavReaderFile.Write(mavenGavReaderContent); err != nil { return fmt.Errorf("failed writing content to the %s file: \n%s", mavenGavReader, err.Error()) } // Install the plugin - var output []byte installProperties := []string{"org.apache.maven.plugins:maven-install-plugin:2.5.2:install-file", "-Dfile=" + mavenGavReaderFile.Name()} - if output, err = exec.Command("mvn", installProperties...).CombinedOutput(); err != nil { - return fmt.Errorf("failed to install the maven-gav-reader plugin. Maven output: %s\n Error received:\n%s", string(output), err.Error()) + if _, err = mph.runMvnCommand(installProperties); err != nil { + return fmt.Errorf("failed to install the maven-gav-reader plugin: %s", err.Error()) } mph.isMavenGavReaderInstalled = true return @@ -241,12 +231,13 @@ func (mph *MavenPackageHandler) installMavenGavReader() (err error) { func (mph *MavenPackageHandler) getProjectPoms() (err error) { // Check if we already scanned the project pom.xml locations if len(mph.pomPaths) > 0 { - return nil + return } goals := []string{"com.jfrog.frogbot:maven-gav-reader:gav", "-q"} var readerOutput []byte if readerOutput, err = mph.runMvnCommand(goals); err != nil { - return fmt.Errorf("failed to get project poms while running maven-gav-reader:\n%s\n%s", readerOutput, err.Error()) + err = fmt.Errorf("failed to get project poms while running maven-gav-reader: %s", err.Error()) + return } for _, jsonContent := range strings.Split(string(readerOutput), "\n") { if jsonContent == "" { @@ -256,12 +247,12 @@ func (mph *MavenPackageHandler) getProjectPoms() (err error) { // Escape backslashes in the pomPath field, to fix windows backslash parsing issues escapedContent := strings.ReplaceAll(jsonContent, `\`, `\\`) if err = json.Unmarshal([]byte(escapedContent), &pp); err != nil { - return err + return } mph.pomPaths = append(mph.pomPaths, pp) } if len(mph.pomPaths) == 0 { - return errors.New("couldn't find any pom.xml files in the current project'") + err = errors.New("couldn't find any pom.xml files in the current project") } return } @@ -289,8 +280,8 @@ func (mph *MavenPackageHandler) updateProperties(depDetails *pomDependencyDetail fmt.Sprintf("-DprocessDependencyManagement=%t", depDetails.foundInDependencyManagement)} updatePropertyCmd := fmt.Sprintf("mvn %s", strings.Join(updatePropertyArgs, " ")) log.Debug(fmt.Sprintf("Running '%s'", updatePropertyCmd)) - if updatePropertyOutput, err := mph.runMvnCommand(updatePropertyArgs); err != nil { // #nosec G204 - return fmt.Errorf("failed updating %s property: %s\n%s", property, err.Error(), updatePropertyOutput) + if _, err := mph.runMvnCommand(updatePropertyArgs); err != nil { // #nosec G204 + return fmt.Errorf("failed updating %s property: %s\n", property, err.Error()) } } return nil @@ -299,7 +290,10 @@ func (mph *MavenPackageHandler) updateProperties(depDetails *pomDependencyDetail func (mph *MavenPackageHandler) runMvnCommand(goals []string) (readerOutput []byte, err error) { if mph.depsRepo == "" { if readerOutput, err = exec.Command("mvn", goals...).CombinedOutput(); err != nil { - return nil, fmt.Errorf("failed running maven command: \n%s\n%s", readerOutput, err.Error()) + if len(readerOutput) > 0 { + log.Info(string(readerOutput)) + } + err = fmt.Errorf("failed running command 'mvn %s': %s", strings.Join(goals, " "), err.Error()) } return } @@ -316,10 +310,13 @@ func (mph *MavenPackageHandler) runMvnCommand(goals []string) (readerOutput []by SetDisableDeploy(true). SetOutputWriter(&buf) if err = mvnutils.RunMvn(mvnParams); err != nil { - return + readerOutput = make([]byte, 0) + _, _ = io.ReadFull(&buf, readerOutput) + if len(readerOutput) > 0 { + // Log output if exists + log.Info(string(readerOutput)) + } + err = fmt.Errorf("failed running command 'mvn %s': %s", strings.Join(goals, " "), err.Error()) } - - readerOutput = make([]byte, buf.Len()) - _, err = io.ReadFull(&buf, readerOutput) return } diff --git a/packagehandlers/packagehandlers_test.go b/packagehandlers/packagehandlers_test.go index a3dc10539..d4f7c3d50 100644 --- a/packagehandlers/packagehandlers_test.go +++ b/packagehandlers/packagehandlers_test.go @@ -42,7 +42,7 @@ func TestUpdateDependency(t *testing.T) { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "0.0.0-20201216223049-8b5274cf687f", IsDirectDependency: false, - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Go, ImpactedDependencyName: "golang.org/x/crypto"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Go, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "golang.org/x/crypto"}}, }, fixSupported: true, uniqueChecksExtraArgs: []string{GoPackageDescriptor}, @@ -51,7 +51,7 @@ func TestUpdateDependency(t *testing.T) { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.7.7", IsDirectDependency: true, - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Go, ImpactedDependencyName: "github.com/gin-gonic/gin"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Go, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "github.com/gin-gonic/gin"}}, }, fixSupported: true, uniqueChecksExtraArgs: []string{GoPackageDescriptor}, @@ -60,7 +60,7 @@ func TestUpdateDependency(t *testing.T) { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.3.0", IsDirectDependency: true, - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Go, ImpactedDependencyName: "github.com/google/uuid"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Go, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "github.com/google/uuid"}}, }, fixSupported: true, uniqueChecksExtraArgs: []string{GoPackageDescriptor}, @@ -72,7 +72,7 @@ func TestUpdateDependency(t *testing.T) { { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.25.9", - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "urllib3"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "urllib3"}}, }, scanDetails: &utils.ScanDetails{Project: &utils.Project{PipRequirementsFile: "requirements.txt"}}, fixSupported: false, @@ -80,7 +80,7 @@ func TestUpdateDependency(t *testing.T) { { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.25.9", - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Poetry, ImpactedDependencyName: "urllib3"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Poetry, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "urllib3"}}, }, scanDetails: &utils.ScanDetails{Project: &utils.Project{PipRequirementsFile: "pyproejct.toml"}}, fixSupported: false, @@ -88,7 +88,7 @@ func TestUpdateDependency(t *testing.T) { { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.25.9", - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pipenv, ImpactedDependencyName: "urllib3"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pipenv, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "urllib3"}}, }, scanDetails: &utils.ScanDetails{Project: &utils.Project{PipRequirementsFile: "Pipfile"}}, fixSupported: false, @@ -96,7 +96,7 @@ func TestUpdateDependency(t *testing.T) { { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "2.4.0", - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "pyjwt"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "pyjwt"}}, IsDirectDependency: true, }, scanDetails: &utils.ScanDetails{Project: &utils.Project{PipRequirementsFile: "requirements.txt"}}, @@ -105,7 +105,7 @@ func TestUpdateDependency(t *testing.T) { { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "2.4.0", - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "Pyjwt"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "Pyjwt"}}, IsDirectDependency: true}, scanDetails: &utils.ScanDetails{Project: &utils.Project{PipRequirementsFile: "requirements.txt"}}, fixSupported: true, @@ -113,7 +113,7 @@ func TestUpdateDependency(t *testing.T) { { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "2.4.0", - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyName: "pyjwt"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Pip, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "pyjwt"}}, IsDirectDependency: true}, scanDetails: &utils.ScanDetails{Project: &utils.Project{PipRequirementsFile: "setup.py"}}, fixSupported: true, @@ -121,7 +121,7 @@ func TestUpdateDependency(t *testing.T) { { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "2.4.0", - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Poetry, ImpactedDependencyName: "pyjwt"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Poetry, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "pyjwt"}}, IsDirectDependency: true}, scanDetails: &utils.ScanDetails{Project: &utils.Project{PipRequirementsFile: "pyproject.toml"}}, fixSupported: true, @@ -133,7 +133,7 @@ func TestUpdateDependency(t *testing.T) { { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "0.8.4", - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Npm, ImpactedDependencyName: "mpath"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Npm, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "mpath"}}, }, fixSupported: false, }, @@ -141,7 +141,7 @@ func TestUpdateDependency(t *testing.T) { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "3.0.2", IsDirectDependency: true, - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Npm, ImpactedDependencyName: "minimatch"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Npm, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "minimatch"}}, }, fixSupported: true, }, @@ -154,7 +154,7 @@ func TestUpdateDependency(t *testing.T) { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.2.6", IsDirectDependency: false, - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Yarn, ImpactedDependencyName: "minimist"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Yarn, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "minimist"}}, }, fixSupported: false, }, @@ -162,7 +162,7 @@ func TestUpdateDependency(t *testing.T) { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.2.6", IsDirectDependency: true, - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Yarn, ImpactedDependencyName: "minimist"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Yarn, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "minimist"}}, }, fixSupported: true, specificTechVersion: "1", @@ -171,7 +171,7 @@ func TestUpdateDependency(t *testing.T) { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.2.6", IsDirectDependency: true, - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Yarn, ImpactedDependencyName: "minimist"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Yarn, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "minimist"}}, }, fixSupported: true, specificTechVersion: "2", @@ -183,7 +183,7 @@ func TestUpdateDependency(t *testing.T) { { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "2.7", - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Maven, ImpactedDependencyName: "commons-io:commons-io"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Maven, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "commons-io:commons-io"}}, IsDirectDependency: true}, scanDetails: &utils.ScanDetails{Project: &utils.Project{DepsRepo: ""}, ServerDetails: nil}, fixSupported: true, @@ -191,7 +191,7 @@ func TestUpdateDependency(t *testing.T) { { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "4.3.20", - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Maven, ImpactedDependencyName: "org.springframework:spring-core"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Maven, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "org.springframework:spring-core"}}, IsDirectDependency: false}, scanDetails: &utils.ScanDetails{Project: &utils.Project{DepsRepo: ""}, ServerDetails: nil}, fixSupported: false, @@ -205,7 +205,7 @@ func TestUpdateDependency(t *testing.T) { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.1.1", IsDirectDependency: false, - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Nuget, ImpactedDependencyName: "snappier"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Nuget, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "snappier"}}, }, fixSupported: false, }, @@ -213,7 +213,7 @@ func TestUpdateDependency(t *testing.T) { vulnDetails: &utils.VulnerabilityDetails{ SuggestedFixedVersion: "1.1.1", IsDirectDependency: true, - VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Nuget, ImpactedDependencyName: "snappier"}, + VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: coreutils.Nuget, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "snappier"}}, }, fixSupported: true, }, @@ -223,10 +223,10 @@ func TestUpdateDependency(t *testing.T) { for _, testBatch := range testCases { for _, test := range testBatch { packageHandler := GetCompatiblePackageHandler(test.vulnDetails, test.scanDetails) - t.Run(fmt.Sprintf("%s:%s direct:%s", test.vulnDetails.Technology.ToString()+test.specificTechVersion, test.vulnDetails.ImpactedDependencyName, strconv.FormatBool(test.vulnDetails.IsDirectDependency)), + t.Run(fmt.Sprintf("%s:%s direct:%s", test.vulnDetails.Technology.String()+test.specificTechVersion, test.vulnDetails.ImpactedDependencyName, strconv.FormatBool(test.vulnDetails.IsDirectDependency)), func(t *testing.T) { testDataDir := getTestDataDir(t, test.vulnDetails.IsDirectDependency) - cleanup := createTempDirAndChdir(t, testDataDir, test.vulnDetails.Technology.ToString()+test.specificTechVersion) + cleanup := createTempDirAndChdir(t, testDataDir, test.vulnDetails.Technology.String()+test.specificTechVersion) defer cleanup() err := packageHandler.UpdateDependency(test.vulnDetails) if test.fixSupported { diff --git a/packagehandlers/pythonpackagehandler.go b/packagehandlers/pythonpackagehandler.go index de3a03e16..650089543 100644 --- a/packagehandlers/pythonpackagehandler.go +++ b/packagehandlers/pythonpackagehandler.go @@ -56,7 +56,7 @@ func (py *PythonPackageHandler) handlePoetry(vulnDetails *utils.VulnerabilityDet return } // Update Poetry lock file as well - return runPackageMangerCommand(coreutils.Poetry.GetExecCommandName(), coreutils.Poetry.ToString(), []string{"update"}) + return runPackageMangerCommand(coreutils.Poetry.GetExecCommandName(), coreutils.Poetry.String(), []string{"update"}) } func (py *PythonPackageHandler) handlePip(vulnDetails *utils.VulnerabilityDetails) (err error) { diff --git a/release/buildAndUpload.sh b/release/buildAndUpload.sh index 41e9b29d3..cd4ef7b99 100755 --- a/release/buildAndUpload.sh +++ b/release/buildAndUpload.sh @@ -9,8 +9,8 @@ build () { exeName="$4" echo "Building $exeName for $GOOS-$GOARCH ..." - CGO_ENABLED=0 jf go build -o "$exeName" -ldflags '-w -extldflags "-static" -X github.com/jfrog/frogbot/utils.FrogbotVersion='$version - chmod +x $exeName + CGO_ENABLED=0 jf go build -o "$exeName" -ldflags '-w -extldflags "-static" -X github.com/jfrog/frogbot/utils.FrogbotVersion='"$version" + chmod +x "$exeName" # Run verification after building plugin for the correct platform of this image. if [[ "$pkg" = "frogbot-linux-386" ]]; then @@ -26,7 +26,7 @@ buildAndUpload () { fileExtension="$4" exeName="frogbot$fileExtension" - build $pkg $goos $goarch $exeName + build "$pkg" "$goos" "$goarch" "$exeName" destPath="$pkgPath/$version/$pkg/$exeName" echo "Uploading $exeName to $destPath ..." diff --git a/scanpullrequest/scanallpullrequests_test.go b/scanpullrequest/scanallpullrequests_test.go index 0ea7fc04d..6d4b3b203 100644 --- a/scanpullrequest/scanallpullrequests_test.go +++ b/scanpullrequest/scanallpullrequests_test.go @@ -140,11 +140,11 @@ func TestScanAllPullRequestsMultiRepo(t *testing.T) { err := scanAllPullRequestsCmd.Run(configAggregator, client) if assert.NoError(t, err) { assert.Len(t, frogbotMessages, 4) - expectedMessage := "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/notApplicableCritical.png)
Critical | Not Applicable | minimist:1.2.5 | minimist:1.2.5 | [0.2.4]
[1.2.6] | CVE-2021-44906 |\n\n
\n\n## 👇 Details\n\n\n**Description:**\n[Minimist](https://github.com/substack/minimist) is a simple and very popular argument parser. It is used by more than 14 million by Mar 2022. This package developers stopped developing it since April 2020 and its community released a [newer version](https://github.com/meszaros-lajos-gyorgy/minimist-lite) supported by the community.\n\n\nAn incomplete fix for [CVE-2020-7598](https://nvd.nist.gov/vuln/detail/CVE-2020-7598) partially blocked prototype pollution attacks. Researchers discovered that it does not check for constructor functions which means they can be overridden. This behavior can be triggered easily when using it insecurely (which is the common usage). For example:\n```\nvar argv = parse(['--_.concat.constructor.prototype.y', '123']);\nt.equal((function(){}).foo, undefined);\nt.equal(argv.y, undefined);\n```\nIn this example, `prototype.y` is assigned with `123` which will be derived to every newly created object. \n\nThis vulnerability can be triggered when the attacker-controlled input is parsed using Minimist without any validation. As always with prototype pollution, the impact depends on the code that follows the attack, but denial of service is almost always guaranteed.\n**Remediation:**\n##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
" + expectedMessage := "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n## 📦 Vulnerable Dependencies\n\n### ✍️ Summary\n\n
\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/notApplicableCritical.png)
Critical | Not Applicable | minimist:1.2.5 | minimist:1.2.5 | [0.2.4]
[1.2.6] | CVE-2021-44906 |\n\n
\n\n## 🔬 Research Details\n\n\n**Description:**\n[Minimist](https://github.com/substack/minimist) is a simple and very popular argument parser. It is used by more than 14 million by Mar 2022. This package developers stopped developing it since April 2020 and its community released a [newer version](https://github.com/meszaros-lajos-gyorgy/minimist-lite) supported by the community.\n\n\nAn incomplete fix for [CVE-2020-7598](https://nvd.nist.gov/vuln/detail/CVE-2020-7598) partially blocked prototype pollution attacks. Researchers discovered that it does not check for constructor functions which means they can be overridden. This behavior can be triggered easily when using it insecurely (which is the common usage). For example:\n```\nvar argv = parse(['--_.concat.constructor.prototype.y', '123']);\nt.equal((function(){}).foo, undefined);\nt.equal(argv.y, undefined);\n```\nIn this example, `prototype.y` is assigned with `123` which will be derived to every newly created object. \n\nThis vulnerability can be triggered when the attacker-controlled input is parsed using Minimist without any validation. As always with prototype pollution, the impact depends on the code that follows the attack, but denial of service is almost always guaranteed.\n**Remediation:**\n##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
" assert.Equal(t, expectedMessage, frogbotMessages[0]) expectedMessage = "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/noVulnerabilityBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
" assert.Equal(t, expectedMessage, frogbotMessages[1]) - expectedMessage = "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | Undetermined | pip-example:1.2.3 | pyjwt:1.7.1 | [2.4.0] | CVE-2022-29217 |\n\n
\n\n## 👇 Details\n\n\n**Description:**\n[PyJWT](https://pypi.org/project/PyJWT) is a Python implementation of the RFC 7519 standard (JSON Web Tokens). [JSON Web Tokens](https://jwt.io/) are an open, industry standard method for representing claims securely between two parties. A JWT comes with an inline signature that is meant to be verified by the receiving application. JWT supports multiple standard algorithms, and the algorithm itself is **specified in the JWT token itself**.\n\nThe PyJWT library uses the signature-verification algorithm that is specified in the JWT token (that is completely attacker-controlled), however - it requires the validating application to pass an `algorithms` kwarg that specifies the expected algorithms in order to avoid key confusion. Unfortunately - a non-default value `algorithms=jwt.algorithms.get_default_algorithms()` exists that allows all algorithms.\nThe PyJWT library also tries to mitigate key confusions in this case, by making sure that public keys are not used as an HMAC secret. For example, HMAC secrets that begin with `-----BEGIN PUBLIC KEY-----` are rejected when encoding a JWT.\n\nIt has been discovered that due to missing key-type checks, in cases where -\n1. The vulnerable application expects to receive a JWT signed with an Elliptic-Curve key (one of the algorithms `ES256`, `ES384`, `ES512`, `EdDSA`)\n2. The vulnerable application decodes the JWT token using the non-default kwarg `algorithms=jwt.algorithms.get_default_algorithms()` (or alternatively, `algorithms` contain both an HMAC-based algorithm and an EC-based algorithm)\n\nAn attacker can create an HMAC-signed (ex. `HS256`) JWT token, using the (well-known!) EC public key as the HMAC key. The validating application will accept this JWT token as a valid token.\n\nFor example, an application might have planned to validate an `EdDSA`-signed token that was generated as follows -\n```python\n# Making a good jwt token that should work by signing it with the private key\nencoded_good = jwt.encode({\"test\": 1234}, priv_key_bytes, algorithm=\"EdDSA\")\n```\nAn attacker in posession of the public key can generate an `HMAC`-signed token to confuse PyJWT - \n```python\n# Using HMAC with the public key to trick the receiver to think that the public key is a HMAC secret\nencoded_bad = jwt.encode({\"test\": 1234}, pub_key_bytes, algorithm=\"HS256\")\n```\n\nThe following vulnerable `decode` call will accept BOTH of the above tokens as valid - \n```\ndecoded = jwt.decode(encoded_good, pub_key_bytes, \nalgorithms=jwt.algorithms.get_default_algorithms())\n```\n**Remediation:**\n##### Development mitigations\n\nUse a specific algorithm instead of `jwt.algorithms.get_default_algorithms`.\nFor example, replace the following call - \n`jwt.decode(encoded_jwt, pub_key_bytes, algorithms=jwt.algorithms.get_default_algorithms())`\nWith -\n`jwt.decode(encoded_jwt, pub_key_bytes, algorithms=[\"ES256\"])`\n\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
" + expectedMessage = "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n## 📦 Vulnerable Dependencies\n\n### ✍️ Summary\n\n
\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | Undetermined | pip-example:1.2.3 | pyjwt:1.7.1 | [2.4.0] | CVE-2022-29217 |\n\n
\n\n## 🔬 Research Details\n\n\n**Description:**\n[PyJWT](https://pypi.org/project/PyJWT) is a Python implementation of the RFC 7519 standard (JSON Web Tokens). [JSON Web Tokens](https://jwt.io/) are an open, industry standard method for representing claims securely between two parties. A JWT comes with an inline signature that is meant to be verified by the receiving application. JWT supports multiple standard algorithms, and the algorithm itself is **specified in the JWT token itself**.\n\nThe PyJWT library uses the signature-verification algorithm that is specified in the JWT token (that is completely attacker-controlled), however - it requires the validating application to pass an `algorithms` kwarg that specifies the expected algorithms in order to avoid key confusion. Unfortunately - a non-default value `algorithms=jwt.algorithms.get_default_algorithms()` exists that allows all algorithms.\nThe PyJWT library also tries to mitigate key confusions in this case, by making sure that public keys are not used as an HMAC secret. For example, HMAC secrets that begin with `-----BEGIN PUBLIC KEY-----` are rejected when encoding a JWT.\n\nIt has been discovered that due to missing key-type checks, in cases where -\n1. The vulnerable application expects to receive a JWT signed with an Elliptic-Curve key (one of the algorithms `ES256`, `ES384`, `ES512`, `EdDSA`)\n2. The vulnerable application decodes the JWT token using the non-default kwarg `algorithms=jwt.algorithms.get_default_algorithms()` (or alternatively, `algorithms` contain both an HMAC-based algorithm and an EC-based algorithm)\n\nAn attacker can create an HMAC-signed (ex. `HS256`) JWT token, using the (well-known!) EC public key as the HMAC key. The validating application will accept this JWT token as a valid token.\n\nFor example, an application might have planned to validate an `EdDSA`-signed token that was generated as follows -\n```python\n# Making a good jwt token that should work by signing it with the private key\nencoded_good = jwt.encode({\"test\": 1234}, priv_key_bytes, algorithm=\"EdDSA\")\n```\nAn attacker in posession of the public key can generate an `HMAC`-signed token to confuse PyJWT - \n```python\n# Using HMAC with the public key to trick the receiver to think that the public key is a HMAC secret\nencoded_bad = jwt.encode({\"test\": 1234}, pub_key_bytes, algorithm=\"HS256\")\n```\n\nThe following vulnerable `decode` call will accept BOTH of the above tokens as valid - \n```\ndecoded = jwt.decode(encoded_good, pub_key_bytes, \nalgorithms=jwt.algorithms.get_default_algorithms())\n```\n**Remediation:**\n##### Development mitigations\n\nUse a specific algorithm instead of `jwt.algorithms.get_default_algorithms`.\nFor example, replace the following call - \n`jwt.decode(encoded_jwt, pub_key_bytes, algorithms=jwt.algorithms.get_default_algorithms())`\nWith -\n`jwt.decode(encoded_jwt, pub_key_bytes, algorithms=[\"ES256\"])`\n\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
" assert.Equal(t, expectedMessage, frogbotMessages[2]) expectedMessage = "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/noVulnerabilityBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
" assert.Equal(t, expectedMessage, frogbotMessages[3]) @@ -182,7 +182,7 @@ func TestScanAllPullRequests(t *testing.T) { err := scanAllPullRequestsCmd.Run(paramsAggregator, client) assert.NoError(t, err) assert.Len(t, frogbotMessages, 2) - expectedMessage := "**🚨 Frogbot scanned this pull request and found the below:**\n\n---\n## 📦 Vulnerable Dependencies\n---\n\n### ✍️ Summary \n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| Critical | Not Applicable | minimist:1.2.5 | minimist:1.2.5 | [0.2.4], [1.2.6] | CVE-2021-44906 |\n\n---\n### 👇 Details\n---\n\n\n#### [ CVE-2021-44906 ] minimist 1.2.5\n\n\n**Description:**\n[Minimist](https://github.com/substack/minimist) is a simple and very popular argument parser. It is used by more than 14 million by Mar 2022. This package developers stopped developing it since April 2020 and its community released a [newer version](https://github.com/meszaros-lajos-gyorgy/minimist-lite) supported by the community.\n\n\nAn incomplete fix for [CVE-2020-7598](https://nvd.nist.gov/vuln/detail/CVE-2020-7598) partially blocked prototype pollution attacks. Researchers discovered that it does not check for constructor functions which means they can be overridden. This behavior can be triggered easily when using it insecurely (which is the common usage). For example:\n```\nvar argv = parse(['--_.concat.constructor.prototype.y', '123']);\nt.equal((function(){}).foo, undefined);\nt.equal(argv.y, undefined);\n```\nIn this example, `prototype.y` is assigned with `123` which will be derived to every newly created object. \n\nThis vulnerability can be triggered when the attacker-controlled input is parsed using Minimist without any validation. As always with prototype pollution, the impact depends on the code that follows the attack, but denial of service is almost always guaranteed.\n**Remediation:**\n##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)" + expectedMessage := "**🚨 Frogbot scanned this pull request and found the below:**\n\n---\n## 📦 Vulnerable Dependencies\n---\n\n### ✍️ Summary\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| Critical | Not Applicable | minimist:1.2.5 | minimist:1.2.5 | [0.2.4], [1.2.6] | CVE-2021-44906 |\n\n---\n## 🔬 Research Details\n---\n\n\n#### [ CVE-2021-44906 ] minimist 1.2.5\n\n\n**Description:**\n[Minimist](https://github.com/substack/minimist) is a simple and very popular argument parser. It is used by more than 14 million by Mar 2022. This package developers stopped developing it since April 2020 and its community released a [newer version](https://github.com/meszaros-lajos-gyorgy/minimist-lite) supported by the community.\n\n\nAn incomplete fix for [CVE-2020-7598](https://nvd.nist.gov/vuln/detail/CVE-2020-7598) partially blocked prototype pollution attacks. Researchers discovered that it does not check for constructor functions which means they can be overridden. This behavior can be triggered easily when using it insecurely (which is the common usage). For example:\n```\nvar argv = parse(['--_.concat.constructor.prototype.y', '123']);\nt.equal((function(){}).foo, undefined);\nt.equal(argv.y, undefined);\n```\nIn this example, `prototype.y` is assigned with `123` which will be derived to every newly created object. \n\nThis vulnerability can be triggered when the attacker-controlled input is parsed using Minimist without any validation. As always with prototype pollution, the impact depends on the code that follows the attack, but denial of service is almost always guaranteed.\n**Remediation:**\n##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)" assert.Equal(t, expectedMessage, frogbotMessages[0]) expectedMessage = "**👍 Frogbot scanned this pull request and found that it did not add vulnerable dependencies.** \n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)" assert.Equal(t, expectedMessage, frogbotMessages[1]) diff --git a/scanpullrequest/scanpullrequest.go b/scanpullrequest/scanpullrequest.go index 757e817e9..9beb54582 100644 --- a/scanpullrequest/scanpullrequest.go +++ b/scanpullrequest/scanpullrequest.go @@ -4,7 +4,9 @@ import ( "context" "errors" "fmt" + "golang.org/x/exp/slices" "os" + "strings" "github.com/jfrog/frogbot/utils" "github.com/jfrog/frogbot/utils/outputwriter" @@ -92,19 +94,14 @@ func scanPullRequest(repo *utils.Repository, client vcsclient.VcsClient) (err er log.Info("-----------------------------------------------------------") // Audit PR code - vulnerabilitiesRows, iacIssues, secretsIssues, sastIssues, err := auditPullRequest(repo, client, pullRequestDetails) + issues, err := auditPullRequest(repo, client) if err != nil { return } - shouldSendExposedSecretsEmail := len(secretsIssues) > 0 && repo.SmtpServer != "" + shouldSendExposedSecretsEmail := issues.SecretsExists() && repo.SmtpServer != "" if shouldSendExposedSecretsEmail { - prSourceDetails := pullRequestDetails.Source - secretsEmailDetails := utils.NewSecretsEmailDetails( - client, repo.GitProvider, - prSourceDetails.Owner, prSourceDetails.Repository, - prSourceDetails.Name, pullRequestDetails.URL, - secretsIssues, repo.EmailDetails) + secretsEmailDetails := utils.NewSecretsEmailDetails(client, repo, issues.Secrets) if err = utils.AlertSecretsExposed(secretsEmailDetails); err != nil { return } @@ -116,7 +113,7 @@ func scanPullRequest(repo *utils.Repository, client vcsclient.VcsClient) (err er } // Create a pull request message - message := createPullRequestMessage(vulnerabilitiesRows, iacIssues, sastIssues, repo.OutputWriter) + message := createPullRequestComment(issues, repo.OutputWriter) // Add SCA scan comment if err = client.AddPullRequestComment(context.Background(), repo.RepoOwner, repo.RepoName, message, int(pullRequestDetails.ID)); err != nil { @@ -125,143 +122,133 @@ func scanPullRequest(repo *utils.Repository, client vcsclient.VcsClient) (err er } // Handle review comments at the pull request - if err = utils.AddReviewComments(repo, int(pullRequestDetails.ID), client, vulnerabilitiesRows, iacIssues, sastIssues); err != nil { + if err = utils.AddReviewComments(repo, int(pullRequestDetails.ID), client, issues); err != nil { err = errors.New("couldn't add review comments: " + err.Error()) return } // Fail the Frogbot task if a security issue is found and Frogbot isn't configured to avoid the failure. - if repo.FailOnSecurityIssues != nil && *repo.FailOnSecurityIssues && isDetectedIssues(vulnerabilitiesRows, iacIssues, sastIssues) { + if toFailTaskStatus(repo, issues) { err = errors.New(securityIssueFoundErr) } return } -func isDetectedIssues(vulnerabilitiesRows []formats.VulnerabilityOrViolationRow, iacRows []formats.SourceCodeRow, sastIssues []formats.SourceCodeRow) bool { - return len(vulnerabilitiesRows) > 0 || len(iacRows) > 0 || len(sastIssues) > 0 +func toFailTaskStatus(repo *utils.Repository, issues *utils.IssuesCollection) bool { + failFlagSet := repo.FailOnSecurityIssues != nil && *repo.FailOnSecurityIssues + return failFlagSet && issues.IssuesExists() } // Downloads Pull Requests branches code and audits them -func auditPullRequest(repoConfig *utils.Repository, client vcsclient.VcsClient, pullRequestDetails vcsclient.PullRequestInfo) (vulnerabilitiesRows []formats.VulnerabilityOrViolationRow, iacRows []formats.SourceCodeRow, secretsRows []formats.SourceCodeRow, sastRows []formats.SourceCodeRow, err error) { - // Download source branch - sourceBranchInfo := pullRequestDetails.Source - sourceBranchWd, cleanupSource, err := utils.DownloadRepoToTempDir(client, sourceBranchInfo.Owner, sourceBranchInfo.Repository, sourceBranchInfo.Name) - if err != nil { - return - } - - // Download target branch (if needed) - targetBranchWd := "" - cleanupTarget := func() error { return nil } - if !repoConfig.IncludeAllVulnerabilities { - targetBranchInfo := pullRequestDetails.Target - targetBranchWd, cleanupTarget, err = utils.DownloadRepoToTempDir(client, targetBranchInfo.Owner, targetBranchInfo.Repository, targetBranchInfo.Name) - if err != nil { - return - } - } - defer func() { - err = errors.Join(err, cleanupSource(), cleanupTarget()) - }() - +func auditPullRequest(repoConfig *utils.Repository, client vcsclient.VcsClient) (issuesCollection *utils.IssuesCollection, err error) { scanDetails := utils.NewScanDetails(client, &repoConfig.Server, &repoConfig.Git). - SetXrayGraphScanParams(repoConfig.Watches, repoConfig.JFrogProjectKey). + SetXrayGraphScanParams(repoConfig.Watches, repoConfig.JFrogProjectKey, true). SetMinSeverity(repoConfig.MinSeverity). SetFixableOnly(repoConfig.FixableOnly). SetFailOnInstallationErrors(*repoConfig.FailOnSecurityIssues) + issuesCollection = &utils.IssuesCollection{} for i := range repoConfig.Projects { scanDetails.SetProject(&repoConfig.Projects[i]) - - // Audit source branch - var sourceResults *audit.Results - workingDirs := utils.GetFullPathWorkingDirs(scanDetails.Project.WorkingDirs, sourceBranchWd) - sourceResults, err = scanDetails.RunInstallAndAudit(workingDirs...) - if err != nil { + var projectIssues *utils.IssuesCollection + if projectIssues, err = auditPullRequestInProject(repoConfig, scanDetails); err != nil { return } + issuesCollection.Append(projectIssues) + } + return +} - // Set JAS output flags - sourceScanResults := sourceResults.ExtendedScanResults - repoConfig.OutputWriter.SetJasOutputFlags(sourceScanResults.EntitledForJas, len(sourceScanResults.ApplicabilityScanResults) > 0) - - // Get all issues that were found in the source branch - if repoConfig.IncludeAllVulnerabilities { - log.Info("Frogbot is configured to show all vulnerabilities") - var allIssuesRows []formats.VulnerabilityOrViolationRow - allIssuesRows, err = getScanVulnerabilitiesRows(sourceResults) - if err != nil { - return - } - vulnerabilitiesRows = append(vulnerabilitiesRows, allIssuesRows...) - iacRows = append(iacRows, xrayutils.PrepareIacs(sourceScanResults.IacScanResults)...) - secretsRows = append(secretsRows, xrayutils.PrepareSecrets(sourceScanResults.SecretsScanResults)...) - sastRows = append(sastRows, xrayutils.PrepareSast(sourceScanResults.SastScanResults)...) - continue - } +func auditPullRequestInProject(repoConfig *utils.Repository, scanDetails *utils.ScanDetails) (auditIssues *utils.IssuesCollection, err error) { + // Download source branch + sourcePullRequestInfo := scanDetails.PullRequestDetails.Source + sourceBranchWd, cleanupSource, err := utils.DownloadRepoToTempDir(scanDetails.Client(), sourcePullRequestInfo.Owner, sourcePullRequestInfo.Repository, sourcePullRequestInfo.Name) + if err != nil { + return + } + defer func() { + err = errors.Join(err, cleanupSource()) + }() - // Set target branch scan details - var targetResults *audit.Results - workingDirs = utils.GetFullPathWorkingDirs(scanDetails.Project.WorkingDirs, targetBranchWd) - targetResults, err = scanDetails.RunInstallAndAudit(workingDirs...) + // Audit source branch + var sourceResults *audit.Results + workingDirs := utils.GetFullPathWorkingDirs(scanDetails.Project.WorkingDirs, sourceBranchWd) + sourceResults, err = scanDetails.RunInstallAndAudit(workingDirs...) + if err != nil { + return + } - if err != nil { - return - } + // Set JAS output flags + sourceScanResults := sourceResults.ExtendedScanResults + repoConfig.OutputWriter.SetJasOutputFlags(sourceScanResults.EntitledForJas, len(sourceScanResults.ApplicabilityScanResults) > 0) - // Get new issues - var newVulnerabilities []formats.VulnerabilityOrViolationRow - var newIacs, newSecrets, newSast []formats.SourceCodeRow - if newVulnerabilities, newIacs, newSecrets, newSast, err = getNewIssues(targetResults, sourceResults); err != nil { + // Get all issues that exist in the source branch + if repoConfig.IncludeAllVulnerabilities { + if auditIssues, err = getAllIssues(sourceResults, repoConfig.AllowedLicenses); err != nil { return } - vulnerabilitiesRows = append(vulnerabilitiesRows, newVulnerabilities...) - iacRows = append(iacRows, newIacs...) - secretsRows = append(secretsRows, newSecrets...) - sastRows = append(sastRows, newSast...) + utils.ConvertSarifPathsToRelative(auditIssues, sourceBranchWd) + return } - convertPathsToRelative(vulnerabilitiesRows, iacRows, secretsRows, sastRows, sourceBranchWd, targetBranchWd) + var targetBranchWd string + if auditIssues, targetBranchWd, err = auditTargetBranch(repoConfig, scanDetails, sourceResults); err != nil { + return + } + utils.ConvertSarifPathsToRelative(auditIssues, sourceBranchWd, targetBranchWd) return } -func convertPathsToRelative(vulnerabilitiesRows []formats.VulnerabilityOrViolationRow, iacRows []formats.SourceCodeRow, secretsRows []formats.SourceCodeRow, sastRows []formats.SourceCodeRow, sourceWd, targetWd string) { - for _, row := range vulnerabilitiesRows { - for _, cve := range row.Cves { - if cve.Applicability != nil { - for i := range cve.Applicability.Evidence { - cve.Applicability.Evidence[i].File = xrayutils.ExtractRelativePath(cve.Applicability.Evidence[i].File, sourceWd) - cve.Applicability.Evidence[i].File = xrayutils.ExtractRelativePath(cve.Applicability.Evidence[i].File, targetWd) - } - } +func auditTargetBranch(repoConfig *utils.Repository, scanDetails *utils.ScanDetails, sourceScanResults *audit.Results) (newIssues *utils.IssuesCollection, targetBranchWd string, err error) { + // Download target branch (if needed) + cleanupTarget := func() error { return nil } + if !repoConfig.IncludeAllVulnerabilities { + targetBranchInfo := repoConfig.PullRequestDetails.Target + if targetBranchWd, cleanupTarget, err = utils.DownloadRepoToTempDir(scanDetails.Client(), targetBranchInfo.Owner, targetBranchInfo.Repository, targetBranchInfo.Name); err != nil { + return } } - for i := range iacRows { - iacRows[i].Location.File = xrayutils.ExtractRelativePath(iacRows[i].Location.File, sourceWd) - iacRows[i].Location.File = xrayutils.ExtractRelativePath(iacRows[i].Location.File, targetWd) - } - for i := range secretsRows { - secretsRows[i].Location.File = xrayutils.ExtractRelativePath(secretsRows[i].Location.File, sourceWd) - secretsRows[i].Location.File = xrayutils.ExtractRelativePath(secretsRows[i].Location.File, targetWd) - } - for i := range sastRows { - sastRows[i].Location.File = xrayutils.ExtractRelativePath(sastRows[i].Location.File, sourceWd) - sastRows[i].Location.File = xrayutils.ExtractRelativePath(sastRows[i].Location.File, targetWd) - for f := range sastRows[i].CodeFlow { - for l := range sastRows[i].CodeFlow[f] { - sastRows[i].CodeFlow[f][l].File = xrayutils.ExtractRelativePath(sastRows[i].CodeFlow[f][l].File, sourceWd) - sastRows[i].CodeFlow[f][l].File = xrayutils.ExtractRelativePath(sastRows[i].CodeFlow[f][l].File, targetWd) - } - } + defer func() { + err = errors.Join(err, cleanupTarget()) + }() + + // Set target branch scan details + var targetResults *audit.Results + workingDirs := utils.GetFullPathWorkingDirs(scanDetails.Project.WorkingDirs, targetBranchWd) + targetResults, err = scanDetails.RunInstallAndAudit(workingDirs...) + if err != nil { + return } + + // Get newly added issues + newIssues, err = getNewlyAddedIssues(targetResults, sourceScanResults, repoConfig.AllowedLicenses) + return +} + +func getAllIssues(results *audit.Results, allowedLicenses []string) (*utils.IssuesCollection, error) { + log.Info("Frogbot is configured to show all vulnerabilities") + scanResults := results.ExtendedScanResults + allVulnerabilitiesRows, violatedLicenses, err := getScanVulnerabilitiesRows(results, allowedLicenses) + if err != nil { + return nil, err + } + return &utils.IssuesCollection{ + Vulnerabilities: allVulnerabilitiesRows, + Iacs: xrayutils.PrepareIacs(scanResults.IacScanResults), + Secrets: xrayutils.PrepareSecrets(scanResults.SecretsScanResults), + Sast: xrayutils.PrepareSast(scanResults.SastScanResults), + Licenses: violatedLicenses, + }, nil } -func getNewIssues(targetResults, sourceResults *audit.Results) ([]formats.VulnerabilityOrViolationRow, []formats.SourceCodeRow, []formats.SourceCodeRow, []formats.SourceCodeRow, error) { - var newVulnerabilities []formats.VulnerabilityOrViolationRow +// Returns all the issues found in the source branch that didn't exist in the target branch. +func getNewlyAddedIssues(targetResults, sourceResults *audit.Results, allowedLicenses []string) (*utils.IssuesCollection, error) { + var newVulnerabilitiesOrViolations []formats.VulnerabilityOrViolationRow + var newLicenses []formats.LicenseRow var err error if len(sourceResults.ExtendedScanResults.XrayResults) > 0 { - if newVulnerabilities, err = createNewVulnerabilitiesRows(targetResults, sourceResults); err != nil { - return nil, nil, nil, nil, err + if newVulnerabilitiesOrViolations, newLicenses, err = createNewVulnerabilitiesRows(targetResults, sourceResults, allowedLicenses); err != nil { + return nil, err } } @@ -286,7 +273,13 @@ func getNewIssues(targetResults, sourceResults *audit.Results) ([]formats.Vulner newSast = createNewSourceCodeRows(targetSastRows, sourceSastRows) } - return newVulnerabilities, newIacs, newSecrets, newSast, nil + return &utils.IssuesCollection{ + Vulnerabilities: newVulnerabilitiesOrViolations, + Iacs: newIacs, + Secrets: newSecrets, + Sast: newSast, + Licenses: newLicenses, + }, nil } func createNewSourceCodeRows(targetResults, sourceResults []formats.SourceCodeRow) []formats.SourceCodeRow { @@ -304,25 +297,98 @@ func createNewSourceCodeRows(targetResults, sourceResults []formats.SourceCodeRo } // Create vulnerabilities rows. The rows should contain only the new issues added by this PR -func createNewVulnerabilitiesRows(targetResults, sourceResults *audit.Results) (vulnerabilitiesRows []formats.VulnerabilityOrViolationRow, err error) { +func createNewVulnerabilitiesRows(targetResults, sourceResults *audit.Results, allowedLicenses []string) (vulnerabilityOrViolationRows []formats.VulnerabilityOrViolationRow, licenseRows []formats.LicenseRow, err error) { targetScanAggregatedResults := aggregateScanResults(targetResults.ExtendedScanResults.XrayResults) sourceScanAggregatedResults := aggregateScanResults(sourceResults.ExtendedScanResults.XrayResults) if len(sourceScanAggregatedResults.Violations) > 0 { - newViolations, err := getNewViolations(targetScanAggregatedResults, sourceScanAggregatedResults, sourceResults) - if err != nil { - return vulnerabilitiesRows, err + return getNewViolations(&targetScanAggregatedResults, &sourceScanAggregatedResults, sourceResults) + } + if len(sourceScanAggregatedResults.Vulnerabilities) > 0 { + if vulnerabilityOrViolationRows, err = getNewSecurityVulnerabilities(&targetScanAggregatedResults, &sourceScanAggregatedResults, sourceResults); err != nil { + return + } + } + var newLicenses []formats.LicenseRow + if newLicenses, err = getNewLicenseRows(&targetScanAggregatedResults, &sourceScanAggregatedResults); err != nil { + return + } + licenseRows = getViolatedLicenses(allowedLicenses, newLicenses) + return +} + +func getNewSecurityVulnerabilities(targetScan, sourceScan *services.ScanResponse, auditResults *audit.Results) (newVulnerabilitiesRows []formats.VulnerabilityOrViolationRow, err error) { + targetVulnerabilitiesRows, err := xrayutils.PrepareVulnerabilities(targetScan.Vulnerabilities, auditResults.ExtendedScanResults, auditResults.IsMultipleRootProject, true) + if err != nil { + return newVulnerabilitiesRows, err + } + sourceVulnerabilitiesRows, err := xrayutils.PrepareVulnerabilities(sourceScan.Vulnerabilities, auditResults.ExtendedScanResults, auditResults.IsMultipleRootProject, true) + if err != nil { + return newVulnerabilitiesRows, err + } + newVulnerabilitiesRows = getUniqueVulnerabilityOrViolationRows(targetVulnerabilitiesRows, sourceVulnerabilitiesRows) + return +} + +func getUniqueVulnerabilityOrViolationRows(targetRows, sourceRows []formats.VulnerabilityOrViolationRow) []formats.VulnerabilityOrViolationRow { + existingRows := make(map[string]formats.VulnerabilityOrViolationRow) + var newRows []formats.VulnerabilityOrViolationRow + for _, row := range targetRows { + existingRows[utils.GetVulnerabiltiesUniqueID(row)] = row + } + for _, row := range sourceRows { + if _, exists := existingRows[utils.GetVulnerabiltiesUniqueID(row)]; !exists { + newRows = append(newRows, row) } - vulnerabilitiesRows = append(vulnerabilitiesRows, newViolations...) - } else if len(sourceScanAggregatedResults.Vulnerabilities) > 0 { - newVulnerabilities, err := getNewVulnerabilities(targetScanAggregatedResults, sourceScanAggregatedResults, sourceResults) - if err != nil { - return vulnerabilitiesRows, err + } + return newRows +} + +func getNewViolations(targetScan, sourceScan *services.ScanResponse, auditResults *audit.Results) (newSecurityViolationsRows []formats.VulnerabilityOrViolationRow, newLicenseViolationsRows []formats.LicenseRow, err error) { + targetSecurityViolationsRows, targetLicenseViolationsRows, _, err := xrayutils.PrepareViolations(targetScan.Violations, auditResults.ExtendedScanResults, auditResults.IsMultipleRootProject, true) + if err != nil { + return + } + sourceSecurityViolationsRows, sourceLicenseViolationsRows, _, err := xrayutils.PrepareViolations(sourceScan.Violations, auditResults.ExtendedScanResults, auditResults.IsMultipleRootProject, true) + if err != nil { + return + } + newSecurityViolationsRows = getUniqueVulnerabilityOrViolationRows(targetSecurityViolationsRows, sourceSecurityViolationsRows) + if len(sourceLicenseViolationsRows) > 0 { + newLicenseViolationsRows = getUniqueLicenseRows(targetLicenseViolationsRows, sourceLicenseViolationsRows) + } + return +} + +func getNewLicenseRows(targetScan, sourceScan *services.ScanResponse) (newLicenses []formats.LicenseRow, err error) { + targetLicenses, err := xrayutils.PrepareLicenses(targetScan.Licenses) + if err != nil { + return + } + sourceLicenses, err := xrayutils.PrepareLicenses(sourceScan.Licenses) + if err != nil { + return + } + newLicenses = getUniqueLicenseRows(targetLicenses, sourceLicenses) + return +} + +func getUniqueLicenseRows(targetRows, sourceRows []formats.LicenseRow) []formats.LicenseRow { + existingLicenses := make(map[string]formats.LicenseRow) + var newLicenses []formats.LicenseRow + for _, row := range targetRows { + existingLicenses[getUniqueLicenseKey(row)] = row + } + for _, row := range sourceRows { + if _, exists := existingLicenses[getUniqueLicenseKey(row)]; !exists { + newLicenses = append(newLicenses, row) } - vulnerabilitiesRows = append(vulnerabilitiesRows, newVulnerabilities...) } + return newLicenses +} - return vulnerabilitiesRows, nil +func getUniqueLicenseKey(license formats.LicenseRow) string { + return license.LicenseKey + license.ImpactedDependencyName + license.ImpactedDependencyType } func aggregateScanResults(scanResults []services.ScanResponse) services.ScanResponse { @@ -338,65 +404,53 @@ func aggregateScanResults(scanResults []services.ScanResponse) services.ScanResp } // Create vulnerability rows. The rows should contain all the issues that were found in this module scan. -func getScanVulnerabilitiesRows(auditResults *audit.Results) ([]formats.VulnerabilityOrViolationRow, error) { - violations, vulnerabilities, _ := xrayutils.SplitScanResults(auditResults.ExtendedScanResults.XrayResults) +func getScanVulnerabilitiesRows(auditResults *audit.Results, allowedLicenses []string) (vulnerabilitiesRows []formats.VulnerabilityOrViolationRow, violatedLicenses []formats.LicenseRow, err error) { + violations, vulnerabilities, licenses := xrayutils.SplitScanResults(auditResults.ExtendedScanResults.XrayResults) if len(violations) > 0 { - violationsRows, _, _, err := xrayutils.PrepareViolations(violations, auditResults.ExtendedScanResults, auditResults.IsMultipleRootProject, true) - return violationsRows, err + var licenseViolationsRows []formats.LicenseRow + if vulnerabilitiesRows, licenseViolationsRows, _, err = xrayutils.PrepareViolations(violations, auditResults.ExtendedScanResults, auditResults.IsMultipleRootProject, true); err != nil { + return nil, nil, err + } + return vulnerabilitiesRows, licenseViolationsRows, err } if len(vulnerabilities) > 0 { - return xrayutils.PrepareVulnerabilities(vulnerabilities, auditResults.ExtendedScanResults, auditResults.IsMultipleRootProject, true) - } - return []formats.VulnerabilityOrViolationRow{}, nil -} - -func getNewViolations(targetScan, sourceScan services.ScanResponse, auditResults *audit.Results) (newViolationsRows []formats.VulnerabilityOrViolationRow, err error) { - existsViolationsMap := make(map[string]formats.VulnerabilityOrViolationRow) - violationsRows, _, _, err := xrayutils.PrepareViolations(targetScan.Violations, auditResults.ExtendedScanResults, auditResults.IsMultipleRootProject, true) - if err != nil { - return violationsRows, err - } - for _, violation := range violationsRows { - existsViolationsMap[utils.GetUniqueID(violation)] = violation - } - violationsRows, _, _, err = xrayutils.PrepareViolations(sourceScan.Violations, auditResults.ExtendedScanResults, auditResults.IsMultipleRootProject, true) - if err != nil { - return newViolationsRows, err - } - for _, violation := range violationsRows { - if _, exists := existsViolationsMap[utils.GetUniqueID(violation)]; !exists { - newViolationsRows = append(newViolationsRows, violation) + if vulnerabilitiesRows, err = xrayutils.PrepareVulnerabilities(vulnerabilities, auditResults.ExtendedScanResults, auditResults.IsMultipleRootProject, true); err != nil { + return } } + var licenseRows []formats.LicenseRow + if licenseRows, err = xrayutils.PrepareLicenses(licenses); err != nil { + return + } + violatedLicenses = getViolatedLicenses(allowedLicenses, licenseRows) return } -func getNewVulnerabilities(targetScan, sourceScan services.ScanResponse, auditResults *audit.Results) (newVulnerabilitiesRows []formats.VulnerabilityOrViolationRow, err error) { - targetVulnerabilitiesMap := make(map[string]formats.VulnerabilityOrViolationRow) - targetVulnerabilitiesRows, err := xrayutils.PrepareVulnerabilities(targetScan.Vulnerabilities, auditResults.ExtendedScanResults, auditResults.IsMultipleRootProject, true) - if err != nil { - return newVulnerabilitiesRows, err - } - for _, vulnerability := range targetVulnerabilitiesRows { - targetVulnerabilitiesMap[utils.GetUniqueID(vulnerability)] = vulnerability - } - sourceVulnerabilitiesRows, err := xrayutils.PrepareVulnerabilities(sourceScan.Vulnerabilities, auditResults.ExtendedScanResults, auditResults.IsMultipleRootProject, true) - if err != nil { - return newVulnerabilitiesRows, err +func getViolatedLicenses(allowedLicenses []string, licenses []formats.LicenseRow) []formats.LicenseRow { + if len(allowedLicenses) == 0 { + return nil } - for _, vulnerability := range sourceVulnerabilitiesRows { - if _, exists := targetVulnerabilitiesMap[utils.GetUniqueID(vulnerability)]; !exists { - newVulnerabilitiesRows = append(newVulnerabilitiesRows, vulnerability) + var violatedLicenses []formats.LicenseRow + for _, license := range licenses { + if !slices.Contains(allowedLicenses, license.LicenseKey) { + violatedLicenses = append(violatedLicenses, license) } } - return + return violatedLicenses } -func createPullRequestMessage(vulnerabilitiesRows []formats.VulnerabilityOrViolationRow, iacIssues, sastIssues []formats.SourceCodeRow, writer outputwriter.OutputWriter) string { - if !isDetectedIssues(vulnerabilitiesRows, iacIssues, sastIssues) { +func createPullRequestComment(issues *utils.IssuesCollection, writer outputwriter.OutputWriter) string { + if !issues.IssuesExists() { return writer.NoVulnerabilitiesTitle() + writer.UntitledForJasMsg() + writer.Footer() } - return writer.VulnerabilitiesTitle(true) + writer.VulnerabilitiesContent(vulnerabilitiesRows) + writer.UntitledForJasMsg() + writer.Footer() + comment := strings.Builder{} + comment.WriteString(writer.VulnerabilitiesTitle(true)) + comment.WriteString(writer.VulnerabilitiesContent(issues.Vulnerabilities)) + comment.WriteString(writer.LicensesContent(issues.Licenses)) + comment.WriteString(writer.UntitledForJasMsg()) + comment.WriteString(writer.Footer()) + + return comment.String() } func deleteExistingPullRequestComment(repository *utils.Repository, client vcsclient.VcsClient) error { diff --git a/scanpullrequest/scanpullrequest_test.go b/scanpullrequest/scanpullrequest_test.go index cb9ce14d8..cead6eaab 100644 --- a/scanpullrequest/scanpullrequest_test.go +++ b/scanpullrequest/scanpullrequest_test.go @@ -44,14 +44,22 @@ const ( func TestCreateVulnerabilitiesRows(t *testing.T) { // Previous scan with only one violation - XRAY-1 previousScan := services.ScanResponse{ - Violations: []services.Violation{{ - IssueId: "XRAY-1", - Summary: "summary-1", - Severity: "high", - Cves: []services.Cve{}, - ViolationType: "security", - Components: map[string]services.Component{"component-A": {}, "component-B": {}}, - }}, + Violations: []services.Violation{ + { + IssueId: "XRAY-1", + Summary: "summary-1", + Severity: "high", + Cves: []services.Cve{}, + ViolationType: "security", + Components: map[string]services.Component{"component-A": {}, "component-B": {}}, + }, + { + IssueId: "XRAY-4", + ViolationType: "license", + LicenseKey: "Apache-2.0", + Components: map[string]services.Component{"Dep-2": {}}, + }, + }, } // Current scan with 2 violations - XRAY-1 and XRAY-2 @@ -71,23 +79,33 @@ func TestCreateVulnerabilitiesRows(t *testing.T) { Severity: "low", Components: map[string]services.Component{"component-C": {}, "component-D": {}}, }, + { + IssueId: "XRAY-3", + ViolationType: "license", + LicenseKey: "MIT", + Components: map[string]services.Component{"Dep-1": {}}, + }, }, } // Run createNewIssuesRows and make sure that only the XRAY-2 violation exists in the results - rows, err := createNewVulnerabilitiesRows( + securityViolationsRows, licenseViolations, err := createNewVulnerabilitiesRows( &audit.Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{XrayResults: []services.ScanResponse{previousScan}}}, &audit.Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}}}, + nil, ) assert.NoError(t, err) - assert.Len(t, rows, 2) - assert.Equal(t, "XRAY-2", rows[0].IssueId) - assert.Equal(t, "low", rows[0].Severity) - assert.Equal(t, "XRAY-2", rows[1].IssueId) - assert.Equal(t, "low", rows[1].Severity) - - impactedPackageOne := rows[0].ImpactedDependencyName - impactedPackageTwo := rows[1].ImpactedDependencyName + assert.Len(t, licenseViolations, 1) + assert.Len(t, securityViolationsRows, 2) + assert.Equal(t, "XRAY-2", securityViolationsRows[0].IssueId) + assert.Equal(t, "low", securityViolationsRows[0].Severity) + assert.Equal(t, "XRAY-2", securityViolationsRows[1].IssueId) + assert.Equal(t, "low", securityViolationsRows[1].Severity) + assert.Equal(t, "MIT", licenseViolations[0].LicenseKey) + assert.Equal(t, "Dep-1", licenseViolations[0].ImpactedDependencyName) + + impactedPackageOne := securityViolationsRows[0].ImpactedDependencyName + impactedPackageTwo := securityViolationsRows[1].ImpactedDependencyName assert.ElementsMatch(t, []string{"component-C", "component-D"}, []string{impactedPackageOne, impactedPackageTwo}) } @@ -114,34 +132,55 @@ func TestCreateVulnerabilitiesRowsCaseNoPrevViolations(t *testing.T) { Severity: "low", Components: map[string]services.Component{"component-C": {}}, }, + { + IssueId: "XRAY-3", + ViolationType: "license", + LicenseKey: "MIT", + Components: map[string]services.Component{"Dep-1": {}}, + }, }, } - expected := []formats.VulnerabilityOrViolationRow{ + expectedVulns := []formats.VulnerabilityOrViolationRow{ { - IssueId: "XRAY-1", - Severity: "high", - ImpactedDependencyName: "component-A", + IssueId: "XRAY-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "high"}, + ImpactedDependencyName: "component-A", + }, + }, + { + IssueId: "XRAY-2", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "low"}, + ImpactedDependencyName: "component-C", + }, }, + } + + expectedLicenses := []formats.LicenseRow{ { - IssueId: "XRAY-2", - Severity: "low", - ImpactedDependencyName: "component-C", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "Dep-1"}, + LicenseKey: "MIT", }, } // Run createNewIssuesRows and expect both XRAY-1 and XRAY-2 violation in the results - rows, err := createNewVulnerabilitiesRows( + vulnerabilities, licenses, err := createNewVulnerabilitiesRows( &audit.Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{XrayResults: []services.ScanResponse{previousScan}}}, &audit.Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}}}, + []string{}, ) assert.NoError(t, err) - assert.Len(t, rows, 2) - assert.ElementsMatch(t, expected, rows) + assert.Len(t, licenses, 1) + assert.Len(t, vulnerabilities, 2) + assert.ElementsMatch(t, expectedVulns, vulnerabilities) + assert.Equal(t, expectedLicenses[0].ImpactedDependencyName, licenses[0].ImpactedDependencyName) + assert.Equal(t, expectedLicenses[0].LicenseKey, licenses[0].LicenseKey) } func TestGetNewViolationsCaseNoNewViolations(t *testing.T) { - // Previous scan with 2 violations - XRAY-1 and XRAY-2 + // Previous scan with 2 security violations and 1 license violation - XRAY-1 and XRAY-2 previousScan := services.ScanResponse{ Violations: []services.Violation{ { @@ -157,6 +196,12 @@ func TestGetNewViolationsCaseNoNewViolations(t *testing.T) { Severity: "low", Components: map[string]services.Component{"component-C": {}}, }, + { + IssueId: "XRAY-3", + LicenseKey: "MIT", + ViolationType: "license", + Components: map[string]services.Component{"component-B": {}}, + }, }, } @@ -166,12 +211,14 @@ func TestGetNewViolationsCaseNoNewViolations(t *testing.T) { } // Run createNewIssuesRows and expect no violations in the results - rows, err := createNewVulnerabilitiesRows( + securityViolations, licenseViolations, err := createNewVulnerabilitiesRows( &audit.Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{XrayResults: []services.ScanResponse{previousScan}}}, &audit.Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}}}, + []string{"MIT"}, ) assert.NoError(t, err) - assert.Len(t, rows, 0) + assert.Len(t, securityViolations, 0) + assert.Len(t, licenseViolations, 0) } func TestGetAllVulnerabilities(t *testing.T) { @@ -195,36 +242,45 @@ func TestGetAllVulnerabilities(t *testing.T) { expected := []formats.VulnerabilityOrViolationRow{ { - Summary: "summary-1", - IssueId: "XRAY-1", - Severity: "high", - ImpactedDependencyName: "component-A", + Summary: "summary-1", + IssueId: "XRAY-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "high"}, + ImpactedDependencyName: "component-A", + }, }, { - Summary: "summary-1", - IssueId: "XRAY-1", - Severity: "high", - ImpactedDependencyName: "component-B", + Summary: "summary-1", + IssueId: "XRAY-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "high"}, + ImpactedDependencyName: "component-B", + }, }, { - Summary: "summary-2", - IssueId: "XRAY-2", - Severity: "low", - ImpactedDependencyName: "component-C", + Summary: "summary-2", + IssueId: "XRAY-2", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "low"}, + ImpactedDependencyName: "component-C", + }, }, { - Summary: "summary-2", - IssueId: "XRAY-2", - Severity: "low", - ImpactedDependencyName: "component-D", + Summary: "summary-2", + IssueId: "XRAY-2", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "low"}, + ImpactedDependencyName: "component-D", + }, }, } // Run createAllIssuesRows and make sure that XRAY-1 and XRAY-2 vulnerabilities exists in the results - rows, err := getScanVulnerabilitiesRows(&audit.Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}}}) + vulnerabilities, licenses, err := getScanVulnerabilitiesRows(&audit.Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}}}, nil) assert.NoError(t, err) - assert.Len(t, rows, 4) - assert.ElementsMatch(t, expected, rows) + assert.Len(t, vulnerabilities, 4) + assert.Len(t, licenses, 0) + assert.ElementsMatch(t, expected, vulnerabilities) } func TestGetNewVulnerabilities(t *testing.T) { @@ -236,7 +292,7 @@ func TestGetNewVulnerabilities(t *testing.T) { Severity: "high", Cves: []services.Cve{{Id: "CVE-2023-1234"}}, Components: map[string]services.Component{"component-A": {}, "component-B": {}}, - Technology: coreutils.Maven.ToString(), + Technology: coreutils.Maven.String(), }}, } @@ -249,7 +305,7 @@ func TestGetNewVulnerabilities(t *testing.T) { Severity: "high", Cves: []services.Cve{{Id: "CVE-2023-1234"}}, Components: map[string]services.Component{"component-A": {}, "component-B": {}}, - Technology: coreutils.Maven.ToString(), + Technology: coreutils.Maven.String(), }, { IssueId: "XRAY-2", @@ -257,48 +313,81 @@ func TestGetNewVulnerabilities(t *testing.T) { Severity: "low", Cves: []services.Cve{{Id: "CVE-2023-4321"}}, Components: map[string]services.Component{"component-C": {}, "component-D": {}}, - Technology: coreutils.Yarn.ToString(), + Technology: coreutils.Yarn.String(), }, }, } expected := []formats.VulnerabilityOrViolationRow{ { - Summary: "summary-2", - Applicable: "Applicable", - IssueId: "XRAY-2", - Severity: "low", - ImpactedDependencyName: "component-C", - Cves: []formats.CveRow{{Id: "CVE-2023-4321", Applicability: &formats.Applicability{Status: "Applicable", Evidence: []formats.Evidence{{Location: formats.Location{File: "file1", StartLine: 1, StartColumn: 10}}}}}}, - Technology: coreutils.Yarn, + Summary: "summary-2", + Applicable: "Applicable", + IssueId: "XRAY-2", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "low"}, + ImpactedDependencyName: "component-C", + }, + Cves: []formats.CveRow{{Id: "CVE-2023-4321", Applicability: &formats.Applicability{Status: "Applicable", Evidence: []formats.Evidence{{Location: formats.Location{File: "file1", StartLine: 1, StartColumn: 10}}}}}}, + Technology: coreutils.Yarn, }, { - Summary: "summary-2", - Applicable: "Applicable", - IssueId: "XRAY-2", - Severity: "low", - Cves: []formats.CveRow{{Id: "CVE-2023-4321", Applicability: &formats.Applicability{Status: "Applicable", Evidence: []formats.Evidence{{Location: formats.Location{File: "file1", StartLine: 1, StartColumn: 10}}}}}}, - ImpactedDependencyName: "component-D", - Technology: coreutils.Yarn, + Summary: "summary-2", + Applicable: "Applicable", + IssueId: "XRAY-2", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "low"}, + ImpactedDependencyName: "component-D", + }, + Cves: []formats.CveRow{{Id: "CVE-2023-4321", Applicability: &formats.Applicability{Status: "Applicable", Evidence: []formats.Evidence{{Location: formats.Location{File: "file1", StartLine: 1, StartColumn: 10}}}}}}, + Technology: coreutils.Yarn, }, } // Run createNewIssuesRows and make sure that only the XRAY-2 vulnerability exists in the results - rows, err := createNewVulnerabilitiesRows( - &audit.Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{XrayResults: []services.ScanResponse{previousScan}, EntitledForJas: true, ApplicabilityScanResults: []*sarif.Run{sarif.NewRunWithInformationURI("", "").WithResults([]*sarif.Result{ - sarif.NewRuleResult("applic_CVE-2023-4321").WithLocations([]*sarif.Location{ - sarif.NewLocationWithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file1")).WithRegion(sarif.NewRegion().WithStartLine(1).WithStartColumn(10))), - }), - })}}}, - &audit.Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}, EntitledForJas: true, ApplicabilityScanResults: []*sarif.Run{sarif.NewRunWithInformationURI("", "").WithResults([]*sarif.Result{ - sarif.NewRuleResult("applic_CVE-2023-4321").WithLocations([]*sarif.Location{ - sarif.NewLocationWithPhysicalLocation(sarif.NewPhysicalLocation().WithArtifactLocation(sarif.NewArtifactLocation().WithUri("file1")).WithRegion(sarif.NewRegion().WithStartLine(1).WithStartColumn(10))), - }), - })}}}, + vulnerabilities, licenses, err := createNewVulnerabilitiesRows( + &audit.Results{ + ExtendedScanResults: &xrayutils.ExtendedScanResults{ + XrayResults: []services.ScanResponse{previousScan}, + EntitledForJas: true, + ApplicabilityScanResults: []*sarif.Run{sarif.NewRunWithInformationURI("", ""). + WithResults([]*sarif.Result{ + sarif.NewRuleResult("applic_CVE-2023-4321"). + WithLocations([]*sarif.Location{ + sarif.NewLocationWithPhysicalLocation(sarif.NewPhysicalLocation(). + WithArtifactLocation(sarif.NewArtifactLocation(). + WithUri("file1")). + WithRegion(sarif.NewRegion(). + WithStartLine(1). + WithStartColumn(10))), + }), + }), + }, + }, + }, + &audit.Results{ + ExtendedScanResults: &xrayutils.ExtendedScanResults{ + XrayResults: []services.ScanResponse{currentScan}, + EntitledForJas: true, + ApplicabilityScanResults: []*sarif.Run{sarif.NewRunWithInformationURI("", ""). + WithResults([]*sarif.Result{ + sarif.NewRuleResult("applic_CVE-2023-4321"). + WithLocations([]*sarif.Location{sarif.NewLocationWithPhysicalLocation(sarif.NewPhysicalLocation(). + WithArtifactLocation(sarif.NewArtifactLocation(). + WithUri("file1")). + WithRegion(sarif.NewRegion(). + WithStartLine(1). + WithStartColumn(10))), + }), + }), + }, + }, + }, + nil, ) assert.NoError(t, err) - assert.Len(t, rows, 2) - assert.ElementsMatch(t, expected, rows) + assert.Len(t, vulnerabilities, 2) + assert.Len(t, licenses, 0) + assert.ElementsMatch(t, expected, vulnerabilities) } func TestGetNewVulnerabilitiesCaseNoPrevVulnerabilities(t *testing.T) { @@ -329,29 +418,35 @@ func TestGetNewVulnerabilitiesCaseNoPrevVulnerabilities(t *testing.T) { expected := []formats.VulnerabilityOrViolationRow{ { - Summary: "summary-2", - IssueId: "XRAY-2", - Severity: "low", - ImpactedDependencyName: "component-B", + Summary: "summary-2", + IssueId: "XRAY-2", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "low"}, + ImpactedDependencyName: "component-B", + }, JfrogResearchInformation: &formats.JfrogResearchInformation{Details: "description-2"}, }, { - Summary: "summary-1", - IssueId: "XRAY-1", - Severity: "high", - ImpactedDependencyName: "component-A", + Summary: "summary-1", + IssueId: "XRAY-1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "high"}, + ImpactedDependencyName: "component-A", + }, JfrogResearchInformation: &formats.JfrogResearchInformation{Details: "description-1"}, }, } // Run createNewIssuesRows and expect both XRAY-1 and XRAY-2 vulnerability in the results - rows, err := createNewVulnerabilitiesRows( + vulnerabilities, licenses, err := createNewVulnerabilitiesRows( &audit.Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{XrayResults: []services.ScanResponse{previousScan}}}, &audit.Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}}}, + nil, ) assert.NoError(t, err) - assert.Len(t, rows, 2) - assert.ElementsMatch(t, expected, rows) + assert.Len(t, vulnerabilities, 2) + assert.Len(t, licenses, 0) + assert.ElementsMatch(t, expected, vulnerabilities) } func TestGetNewVulnerabilitiesCaseNoNewVulnerabilities(t *testing.T) { @@ -379,17 +474,19 @@ func TestGetNewVulnerabilitiesCaseNoNewVulnerabilities(t *testing.T) { } // Run createNewIssuesRows and expect no vulnerability in the results - rows, err := createNewVulnerabilitiesRows( + vulnerabilities, licenses, err := createNewVulnerabilitiesRows( &audit.Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{XrayResults: []services.ScanResponse{previousScan}}}, &audit.Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{XrayResults: []services.ScanResponse{currentScan}}}, + nil, ) assert.NoError(t, err) - assert.Len(t, rows, 0) + assert.Len(t, vulnerabilities, 0) + assert.Len(t, licenses, 0) } func TestCreatePullRequestMessageNoVulnerabilities(t *testing.T) { vulnerabilities := []formats.VulnerabilityOrViolationRow{} - message := createPullRequestMessage(vulnerabilities, nil, nil, &outputwriter.StandardOutput{}) + message := createPullRequestComment(&utils.IssuesCollection{Vulnerabilities: vulnerabilities}, &outputwriter.StandardOutput{}) expectedMessageByte, err := os.ReadFile(filepath.Join("..", "testdata", "messages", "novulnerabilities.md")) assert.NoError(t, err) @@ -398,7 +495,7 @@ func TestCreatePullRequestMessageNoVulnerabilities(t *testing.T) { outputWriter := &outputwriter.StandardOutput{} outputWriter.SetVcsProvider(vcsutils.GitLab) - message = createPullRequestMessage(vulnerabilities, nil, nil, outputWriter) + message = createPullRequestComment(&utils.IssuesCollection{Vulnerabilities: vulnerabilities}, outputWriter) expectedMessageByte, err = os.ReadFile(filepath.Join("..", "testdata", "messages", "novulnerabilitiesMR.md")) assert.NoError(t, err) @@ -406,61 +503,134 @@ func TestCreatePullRequestMessageNoVulnerabilities(t *testing.T) { assert.Equal(t, expectedMessage, message) } -func TestCreatePullRequestMessage(t *testing.T) { +func TestGetAllIssues(t *testing.T) { + allowedLicenses := []string{"MIT"} + auditResults := &audit.Results{ + ExtendedScanResults: &xrayutils.ExtendedScanResults{ + XrayResults: []services.ScanResponse{{ + Vulnerabilities: []services.Vulnerability{ + {Cves: []services.Cve{{Id: "CVE-2022-2122"}}, Severity: "High", Components: map[string]services.Component{"Dep-1": {FixedVersions: []string{"1.2.3"}}}}, + {Cves: []services.Cve{{Id: "CVE-2023-3122"}}, Severity: "Low", Components: map[string]services.Component{"Dep-2": {FixedVersions: []string{"1.2.2"}}}}, + }, + Licenses: []services.License{{Key: "Apache-2.0", Components: map[string]services.Component{"Dep-1": {FixedVersions: []string{"1.2.3"}}}}}, + }}, + ApplicabilityScanResults: []*sarif.Run{ + utils.GetRunWithDummyResults( + utils.GetDummyResultWithOneLocation("file", 0, 0, "", "applic_CVE-2022-2122", ""), + utils.GetDummyPassingResult("applic_CVE-2023-3122")), + }, + SecretsScanResults: []*sarif.Run{ + utils.GetRunWithDummyResults( + utils.GetDummyResultWithOneLocation("index.js", 2, 13, "access token exposed", "", ""), + ), + }, + EntitledForJas: true, + }, + } + issuesRows, err := getAllIssues(auditResults, allowedLicenses) + assert.NoError(t, err) + assert.Len(t, issuesRows.Licenses, 1) + assert.Len(t, issuesRows.Vulnerabilities, 2) + assert.Len(t, issuesRows.Secrets, 1) + assert.Equal(t, auditResults.ExtendedScanResults.XrayResults[0].Licenses[0].Key, "Apache-2.0") + assert.Equal(t, "Dep-1", issuesRows.Licenses[0].ImpactedDependencyName) + vuln1 := auditResults.ExtendedScanResults.XrayResults[0].Vulnerabilities[0] + assert.Equal(t, vuln1.Cves[0].Id, issuesRows.Vulnerabilities[0].Cves[0].Id) + assert.Equal(t, vuln1.Severity, issuesRows.Vulnerabilities[0].Severity) + assert.Equal(t, vuln1.Components["Dep-1"].FixedVersions[0], issuesRows.Vulnerabilities[0].FixedVersions[0]) + vuln2 := auditResults.ExtendedScanResults.XrayResults[0].Vulnerabilities[1] + assert.Equal(t, vuln2.Cves[0].Id, issuesRows.Vulnerabilities[1].Cves[0].Id) + assert.Equal(t, vuln2.Severity, issuesRows.Vulnerabilities[1].Severity) + assert.Equal(t, vuln2.Components["Dep-2"].FixedVersions[0], issuesRows.Vulnerabilities[1].FixedVersions[0]) + assert.Equal(t, auditResults.ExtendedScanResults.XrayResults[0].Licenses[0].Key, issuesRows.Licenses[0].LicenseKey) + assert.Equal(t, "Dep-1", issuesRows.Licenses[0].ImpactedDependencyName) + assert.Equal(t, xrayutils.GetResultSeverity(auditResults.ExtendedScanResults.SecretsScanResults[0].Results[0]), issuesRows.Secrets[0].Severity) + assert.Equal(t, xrayutils.GetLocationFileName(auditResults.ExtendedScanResults.SecretsScanResults[0].Results[0].Locations[0]), issuesRows.Secrets[0].File) + assert.Equal(t, *auditResults.ExtendedScanResults.SecretsScanResults[0].Results[0].Locations[0].PhysicalLocation.Region.Snippet.Text, issuesRows.Secrets[0].Snippet) +} + +func TestCreatePullRequestComment(t *testing.T) { vulnerabilities := []formats.VulnerabilityOrViolationRow{ { - Severity: "High", - Applicable: "Undetermined", - ImpactedDependencyName: "github.com/nats-io/nats-streaming-server", - ImpactedDependencyVersion: "v0.21.0", - FixedVersions: []string{"[0.24.1]"}, - Components: []formats.ComponentRow{ - { - Name: "github.com/nats-io/nats-streaming-server", - Version: "v0.21.0", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "github.com/nats-io/nats-streaming-server", + ImpactedDependencyVersion: "v0.21.0", + Components: []formats.ComponentRow{ + { + Name: "github.com/nats-io/nats-streaming-server", + Version: "v0.21.0", + }, }, }, - IssueId: "XRAY-122345", - Cves: []formats.CveRow{{}}, + Applicable: "Undetermined", + FixedVersions: []string{"[0.24.1]"}, + IssueId: "XRAY-122345", + Cves: []formats.CveRow{{}}, }, { - Severity: "High", - Applicable: "Undetermined", - ImpactedDependencyName: "github.com/mholt/archiver/v3", - ImpactedDependencyVersion: "v3.5.1", - Components: []formats.ComponentRow{ - { - Name: "github.com/mholt/archiver/v3", - Version: "v3.5.1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "github.com/mholt/archiver/v3", + ImpactedDependencyVersion: "v3.5.1", + Components: []formats.ComponentRow{ + { + Name: "github.com/mholt/archiver/v3", + Version: "v3.5.1", + }, }, }, - Cves: []formats.CveRow{}, + Applicable: "Undetermined", + Cves: []formats.CveRow{}, }, { - Severity: "Medium", - Applicable: "Undetermined", - ImpactedDependencyName: "github.com/nats-io/nats-streaming-server", - ImpactedDependencyVersion: "v0.21.0", - FixedVersions: []string{"[0.24.3]"}, - Components: []formats.ComponentRow{ - { - Name: "github.com/nats-io/nats-streaming-server", - Version: "v0.21.0", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "Medium"}, + ImpactedDependencyName: "github.com/nats-io/nats-streaming-server", + ImpactedDependencyVersion: "v0.21.0", + Components: []formats.ComponentRow{ + { + Name: "github.com/nats-io/nats-streaming-server", + Version: "v0.21.0", + }, + }, + }, + Applicable: "Undetermined", + FixedVersions: []string{"[0.24.3]"}, + Cves: []formats.CveRow{{Id: "CVE-2022-26652"}}, + }, + } + licenses := []formats.LicenseRow{ + { + LicenseKey: "Apache-2.0", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 13}, + ImpactedDependencyName: "minimatch", + ImpactedDependencyVersion: "1.2.3", + Components: []formats.ComponentRow{ + { + Name: "root", + Version: "1.0.0", + }, + { + Name: "minimatch", + Version: "1.2.3", + }, }, }, - Cves: []formats.CveRow{{Id: "CVE-2022-26652"}}, }, } + writerOutput := &outputwriter.StandardOutput{} writerOutput.SetJasOutputFlags(true, true) - message := createPullRequestMessage(vulnerabilities, nil, nil, writerOutput) + message := createPullRequestComment(&utils.IssuesCollection{Vulnerabilities: vulnerabilities, Licenses: licenses}, writerOutput) - expectedMessage := "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | Undetermined | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.1] | - |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | Undetermined | github.com/mholt/archiver/v3:v3.5.1 | github.com/mholt/archiver/v3:v3.5.1 | - | - |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableMediumSeverity.png)
Medium | Undetermined | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.3] | CVE-2022-26652 |\n\n
\n\n## 👇 Details\n\n
\n [ XRAY-122345 ] github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n\n
\n\n\n
\n github.com/mholt/archiver/v3 v3.5.1 \n
\n\n\n
\n\n\n
\n [ CVE-2022-26652 ] github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n\n
\n\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
" + expectedMessage := "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n## 📦 Vulnerable Dependencies\n\n### ✍️ Summary\n\n
\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | Undetermined | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.1] | - |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | Undetermined | github.com/mholt/archiver/v3:v3.5.1 | github.com/mholt/archiver/v3:v3.5.1 | - | - |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableMediumSeverity.png)
Medium | Undetermined | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.3] | CVE-2022-26652 |\n\n
\n\n## 🔬 Research Details\n\n
\n [ XRAY-122345 ] github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n\n
\n\n\n
\n github.com/mholt/archiver/v3 v3.5.1 \n
\n\n\n
\n\n\n
\n [ CVE-2022-26652 ] github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n\n
\n\n\n## ⚖️ Violated Licenses \n\n
\n\n\n| LICENSE | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | \n| :---------------------: | :----------------------------------: | :-----------------------------------: | \n| Apache-2.0 | root 1.0.0
minimatch 1.2.3 | minimatch 1.2.3 |\n\n
\n\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
" assert.Equal(t, expectedMessage, message) writerOutput.SetVcsProvider(vcsutils.GitLab) - message = createPullRequestMessage(vulnerabilities, nil, nil, writerOutput) - expectedMessage = "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerMR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | Undetermined | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.1] | - |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | Undetermined | github.com/mholt/archiver/v3:v3.5.1 | github.com/mholt/archiver/v3:v3.5.1 | - | - |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableMediumSeverity.png)
Medium | Undetermined | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.3] | CVE-2022-26652 |\n\n
\n\n## 👇 Details\n\n
\n [ XRAY-122345 ] github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n\n
\n\n\n
\n github.com/mholt/archiver/v3 v3.5.1 \n
\n\n\n
\n\n\n
\n [ CVE-2022-26652 ] github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n\n
\n\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
" + message = createPullRequestComment(&utils.IssuesCollection{Vulnerabilities: vulnerabilities}, writerOutput) + expectedMessage = "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerMR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n## 📦 Vulnerable Dependencies\n\n### ✍️ Summary\n\n
\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | Undetermined | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.1] | - |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | Undetermined | github.com/mholt/archiver/v3:v3.5.1 | github.com/mholt/archiver/v3:v3.5.1 | - | - |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableMediumSeverity.png)
Medium | Undetermined | github.com/nats-io/nats-streaming-server:v0.21.0 | github.com/nats-io/nats-streaming-server:v0.21.0 | [0.24.3] | CVE-2022-26652 |\n\n
\n\n## 🔬 Research Details\n\n
\n [ XRAY-122345 ] github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n\n
\n\n\n
\n github.com/mholt/archiver/v3 v3.5.1 \n
\n\n\n
\n\n\n
\n [ CVE-2022-26652 ] github.com/nats-io/nats-streaming-server v0.21.0 \n
\n\n\n
\n\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
" assert.Equal(t, expectedMessage, message) } @@ -743,14 +913,16 @@ func TestCreateNewIacRows(t *testing.T) { }, expectedAddedIacVulnerabilities: []formats.SourceCodeRow{ { - Severity: "High", + SeverityDetails: formats.SeverityDetails{ + Severity: "High", + SeverityNumValue: 13, + }, Location: formats.Location{ File: "file1", StartLine: 1, StartColumn: 10, Snippet: "aws violation", }, - SeverityNumValue: 13, }, }, }, @@ -774,8 +946,10 @@ func TestCreateNewIacRows(t *testing.T) { }, expectedAddedIacVulnerabilities: []formats.SourceCodeRow{ { - Severity: "Medium", - SeverityNumValue: 11, + SeverityDetails: formats.SeverityDetails{ + Severity: "Medium", + SeverityNumValue: 11, + }, Location: formats.Location{ File: "file2", StartLine: 2, @@ -830,15 +1004,17 @@ func TestCreateNewSecretRows(t *testing.T) { }, expectedAddedSecretsVulnerabilities: []formats.SourceCodeRow{ { - Severity: "High", - Finding: "Secret", + SeverityDetails: formats.SeverityDetails{ + Severity: "High", + SeverityNumValue: 13, + }, + Finding: "Secret", Location: formats.Location{ File: "file1", StartLine: 1, StartColumn: 10, Snippet: "Sensitive information", }, - SeverityNumValue: 13, }, }, }, @@ -862,9 +1038,11 @@ func TestCreateNewSecretRows(t *testing.T) { }, expectedAddedSecretsVulnerabilities: []formats.SourceCodeRow{ { - Severity: "Medium", - Finding: "Secret", - SeverityNumValue: 11, + SeverityDetails: formats.SeverityDetails{ + Severity: "Medium", + SeverityNumValue: 11, + }, + Finding: "Secret", Location: formats.Location{ File: "file2", StartLine: 2, diff --git a/scanrepository/scanrepository.go b/scanrepository/scanrepository.go index 8537e9a97..256b55a1e 100644 --- a/scanrepository/scanrepository.go +++ b/scanrepository/scanrepository.go @@ -40,7 +40,7 @@ type ScanRepositoryCmd struct { // Determines whether to open a pull request for each vulnerability fix or to aggregate all fixes into one pull request aggregateFixes bool // The current project technology - projectTech coreutils.Technology + projectTech []coreutils.Technology // Stores all package manager handlers for detected issues handlers map[coreutils.Technology]packagehandlers.PackageHandler } @@ -81,7 +81,7 @@ func (cfp *ScanRepositoryCmd) scanAndFixBranch(repository *utils.Repository) (er }() for i := range repository.Projects { cfp.scanDetails.Project = &repository.Projects[i] - cfp.projectTech = "" + cfp.projectTech = []coreutils.Technology{} if err = cfp.scanAndFixProject(repository); err != nil { return } @@ -90,9 +90,8 @@ func (cfp *ScanRepositoryCmd) scanAndFixBranch(repository *utils.Repository) (er } func (cfp *ScanRepositoryCmd) setCommandPrerequisites(repository *utils.Repository, branch string, client vcsclient.VcsClient) (err error) { - cfp.scanDetails = utils.NewScanDetails(client, &repository.Server, &repository.Git). - SetXrayGraphScanParams(repository.Watches, repository.JFrogProjectKey). + SetXrayGraphScanParams(repository.Watches, repository.JFrogProjectKey, false). SetFailOnInstallationErrors(*repository.FailOnSecurityIssues). SetBaseBranch(branch). SetFixableOnly(repository.FixableOnly). @@ -164,6 +163,7 @@ func (cfp *ScanRepositoryCmd) scan(currentWorkingDir string) (*audit.Results, er contextualAnalysisResultsExists := len(auditResults.ExtendedScanResults.ApplicabilityScanResults) > 0 entitledForJas := auditResults.ExtendedScanResults.EntitledForJas cfp.OutputWriter.SetJasOutputFlags(entitledForJas, contextualAnalysisResultsExists) + cfp.projectTech = auditResults.ExtendedScanResults.ScannedTechnologies return auditResults, nil } @@ -356,22 +356,22 @@ func (cfp *ScanRepositoryCmd) openAggregatedPullRequest(fixBranchName string, pu return cfp.scanDetails.Client().CreatePullRequest(context.Background(), cfp.scanDetails.RepoOwner, cfp.scanDetails.RepoName, fixBranchName, cfp.scanDetails.BaseBranch(), pullRequestTitle, prBody) } log.Info("Updating Pull Request from:", fixBranchName, "to:", cfp.scanDetails.BaseBranch()) - return cfp.scanDetails.Client().UpdatePullRequest(context.Background(), cfp.scanDetails.RepoOwner, cfp.scanDetails.RepoName, pullRequestTitle, prBody, "", int(pullRequestInfo.ID), vcsutils.Open) + return cfp.scanDetails.Client().UpdatePullRequest(context.Background(), cfp.scanDetails.RepoOwner, cfp.scanDetails.RepoName, pullRequestTitle, prBody, pullRequestInfo.Target.Name, int(pullRequestInfo.ID), vcsutils.Open) } -func (cfp *ScanRepositoryCmd) preparePullRequestDetails(vulnerabilitiesDetails ...*utils.VulnerabilityDetails) (string, string, error) { +func (cfp *ScanRepositoryCmd) preparePullRequestDetails(vulnerabilitiesDetails ...*utils.VulnerabilityDetails) (prTitle string, prBody string, err error) { if cfp.dryRun && cfp.aggregateFixes { // For testings, don't compare pull request body as scan results order may change. - return outputwriter.GetAggregatedPullRequestTitle(cfp.projectTech), "", nil + return cfp.gitManager.GenerateAggregatedPullRequestTitle(cfp.projectTech), "", nil } vulnerabilitiesRows := utils.ExtractVulnerabilitiesDetailsToRows(vulnerabilitiesDetails) - prBody := cfp.OutputWriter.VulnerabilitiesTitle(false) + "\n" + cfp.OutputWriter.VulnerabilitiesContent(vulnerabilitiesRows) + "\n---\n" + cfp.OutputWriter.UntitledForJasMsg() + cfp.OutputWriter.Footer() + prBody = cfp.OutputWriter.VulnerabilitiesTitle(false) + "\n" + cfp.OutputWriter.VulnerabilitiesContent(vulnerabilitiesRows) + cfp.OutputWriter.UntitledForJasMsg() + cfp.OutputWriter.Footer() if cfp.aggregateFixes { - scanHash, err := utils.VulnerabilityDetailsToMD5Hash(vulnerabilitiesRows...) - if err != nil { - return "", "", err + var scanHash string + if scanHash, err = utils.VulnerabilityDetailsToMD5Hash(vulnerabilitiesRows...); err != nil { + return } - return outputwriter.GetAggregatedPullRequestTitle(cfp.projectTech), prBody + outputwriter.MarkdownComment(fmt.Sprintf("Checksum: %s", scanHash)), nil + return cfp.gitManager.GenerateAggregatedPullRequestTitle(cfp.projectTech), prBody + outputwriter.MarkdownComment(fmt.Sprintf("Checksum: %s", scanHash)), nil } // In separate pull requests there is only one vulnerability vulnDetails := vulnerabilitiesDetails[0] @@ -436,8 +436,8 @@ func (cfp *ScanRepositoryCmd) addVulnerabilityToFixVersionsMap(vulnerability *fo if len(vulnerability.FixedVersions) == 0 { return nil } - if cfp.projectTech == "" { - cfp.projectTech = vulnerability.Technology + if len(cfp.projectTech) == 0 { + cfp.projectTech = []coreutils.Technology{vulnerability.Technology} } vulnFixVersion := getMinimalFixVersion(vulnerability.ImpactedDependencyVersion, vulnerability.FixedVersions) if vulnFixVersion == "" { diff --git a/scanrepository/scanrepository_test.go b/scanrepository/scanrepository_test.go index a8dc66448..8dfa90e3e 100644 --- a/scanrepository/scanrepository_test.go +++ b/scanrepository/scanrepository_test.go @@ -33,16 +33,16 @@ var testPackagesData = []struct { commandArgs []string }{ { - packageType: coreutils.Go.ToString(), + packageType: coreutils.Go.String(), }, { - packageType: coreutils.Maven.ToString(), + packageType: coreutils.Maven.String(), }, { - packageType: coreutils.Gradle.ToString(), + packageType: coreutils.Gradle.String(), }, { - packageType: coreutils.Npm.ToString(), + packageType: coreutils.Npm.String(), commandName: "npm", commandArgs: []string{"install"}, }, @@ -57,18 +57,18 @@ var testPackagesData = []struct { commandArgs: []string{"install"}, }, { - packageType: coreutils.Nuget.ToString(), + packageType: coreutils.Nuget.String(), commandName: "nuget", commandArgs: []string{"restore"}, }, { - packageType: coreutils.Pip.ToString(), + packageType: coreutils.Pip.String(), }, { - packageType: coreutils.Pipenv.ToString(), + packageType: coreutils.Pipenv.String(), }, { - packageType: coreutils.Poetry.ToString(), + packageType: coreutils.Poetry.String(), }, } @@ -98,8 +98,8 @@ func TestScanRepositoryCmd_Run(t *testing.T) { }, { testName: "aggregate-multi-project", - expectedPackagesInBranch: map[string][]string{"frogbot-update-npm-dependencies": {"uuid", "minimatch", "mpath"}, "frogbot-update-pip-dependencies": {"pyjwt", "pexpect"}}, - expectedVersionUpdatesInBranch: map[string][]string{"frogbot-update-npm-dependencies": {"^9.0.0", "^0.8.4", "^3.0.5"}, "frogbot-update-pip-dependencies": {"2.4.0"}}, + expectedPackagesInBranch: map[string][]string{"frogbot-update-npm-dependencies": {"uuid", "minimatch", "mpath"}, "frogbot-update-Pip-dependencies": {"pyjwt", "pexpect"}}, + expectedVersionUpdatesInBranch: map[string][]string{"frogbot-update-npm-dependencies": {"^9.0.0", "^0.8.4", "^3.0.5"}, "frogbot-update-Pip-dependencies": {"2.4.0"}}, packageDescriptorPaths: []string{"npm/package.json", "pip/requirements.txt"}, aggregateFixes: true, configPath: "../testdata/scanrepository/cmd/aggregate-multi-project/.frogbot/frogbot-config.yml", @@ -113,8 +113,8 @@ func TestScanRepositoryCmd_Run(t *testing.T) { }, { testName: "aggregate-cant-fix", - expectedPackagesInBranch: map[string][]string{"frogbot-update-pip-dependencies": {}}, - expectedVersionUpdatesInBranch: map[string][]string{"frogbot-update-pip-dependencies": {}}, + expectedPackagesInBranch: map[string][]string{"frogbot-update-Pip-dependencies": {}}, + expectedVersionUpdatesInBranch: map[string][]string{"frogbot-update-Pip-dependencies": {}}, packageDescriptorPaths: []string{"setup.py"}, // This is a build tool dependency which should not be fixed aggregateFixes: true, }, @@ -374,7 +374,7 @@ func TestPackageTypeFromScan(t *testing.T) { }() assert.NoError(t, err) assert.NoError(t, biutils.CopyDir(projectPath, tmpDir, true, nil)) - if pkg.packageType == coreutils.Gradle.ToString() { + if pkg.packageType == coreutils.Gradle.String() { assert.NoError(t, os.Chmod(filepath.Join(tmpDir, "gradlew"), 0777)) assert.NoError(t, os.Chmod(filepath.Join(tmpDir, "gradlew.bat"), 0777)) } @@ -556,7 +556,7 @@ func TestUpdatePackageToFixedVersion(t *testing.T) { var testScan ScanRepositoryCmd for tech, buildToolsDependencies := range utils.BuildToolsDependenciesMap { for _, impactedDependency := range buildToolsDependencies { - vulnDetails := &utils.VulnerabilityDetails{SuggestedFixedVersion: "3.3.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: tech, ImpactedDependencyName: impactedDependency}, IsDirectDependency: true} + vulnDetails := &utils.VulnerabilityDetails{SuggestedFixedVersion: "3.3.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{Technology: tech, ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: impactedDependency}}, IsDirectDependency: true} err := testScan.updatePackageToFixedVersion(vulnDetails) assert.Error(t, err, "Expected error to occur") assert.IsType(t, &utils.ErrUnsupportedFix{}, err, "Expected unsupported fix error") @@ -660,46 +660,51 @@ random body func TestPreparePullRequestDetails(t *testing.T) { cfp := ScanRepositoryCmd{OutputWriter: &outputwriter.StandardOutput{}, gitManager: &utils.GitManager{}} + cfp.OutputWriter.SetJasOutputFlags(true, false) vulnerabilities := []*utils.VulnerabilityDetails{ { VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ - Summary: "summary", - Severity: "High", - ImpactedDependencyName: "package1", - ImpactedDependencyVersion: "1.0.0", - FixedVersions: []string{"1.0.0", "2.0.0"}, - Cves: []formats.CveRow{{Id: "CVE-2022-1234"}}, + Summary: "summary", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 10}, + ImpactedDependencyName: "package1", + ImpactedDependencyVersion: "1.0.0", + }, + FixedVersions: []string{"1.0.0", "2.0.0"}, + Cves: []formats.CveRow{{Id: "CVE-2022-1234"}}, }, SuggestedFixedVersion: "1.0.0", }, } - expectedPrBody := "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesFixBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n\n| SEVERITY | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | | package1:1.0.0 | 1.0.0
2.0.0 | CVE-2022-1234 |\n\n
\n\n## 👇 Details\n\n\n**Description:**\nsummary\n\n\n---\n\n
\n\n**Frogbot** also supports **Contextual Analysis, Secret Detection and IaC Vulnerabilities Scanning**. This features are included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system.\n\n
\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
" + expectedPrBody := "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesFixBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n\n## 📦 Vulnerable Dependencies\n\n### ✍️ Summary\n\n
\n\n\n| SEVERITY | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | | package1:1.0.0 | 1.0.0
2.0.0 | CVE-2022-1234 |\n\n
\n\n## 🔬 Research Details\n\n\n**Description:**\nsummary\n\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
" prTitle, prBody, err := cfp.preparePullRequestDetails(vulnerabilities...) assert.NoError(t, err) assert.Equal(t, "[🐸 Frogbot] Update version of package1 to 1.0.0", prTitle) assert.Equal(t, expectedPrBody, prBody) vulnerabilities = append(vulnerabilities, &utils.VulnerabilityDetails{ VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ - Summary: "summary", - Severity: "Critical", - ImpactedDependencyName: "package2", - ImpactedDependencyVersion: "2.0.0", - FixedVersions: []string{"2.0.0", "3.0.0"}, - Cves: []formats.CveRow{{Id: "CVE-2022-4321"}}, + Summary: "summary", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "Critical", SeverityNumValue: 12}, + ImpactedDependencyName: "package2", + ImpactedDependencyVersion: "2.0.0", + }, + FixedVersions: []string{"2.0.0", "3.0.0"}, + Cves: []formats.CveRow{{Id: "CVE-2022-4321"}}, }, SuggestedFixedVersion: "2.0.0", }) cfp.aggregateFixes = true - expectedPrBody = "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesFixBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n
\n\n\n| SEVERITY | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | | package1:1.0.0 | 1.0.0
2.0.0 | CVE-2022-1234 |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableCriticalSeverity.png)
Critical | | package2:2.0.0 | 2.0.0
3.0.0 | CVE-2022-4321 |\n\n
\n\n## 👇 Details\n\n
\n [ CVE-2022-1234 ] package1 1.0.0 \n
\n\n**Description:**\nsummary\n\n\n
\n\n\n
\n [ CVE-2022-4321 ] package2 2.0.0 \n
\n\n**Description:**\nsummary\n\n\n
\n\n\n---\n\n
\n\n**Frogbot** also supports **Contextual Analysis, Secret Detection and IaC Vulnerabilities Scanning**. This features are included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system.\n\n
\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n\n[comment]: <> (Checksum: bec823edaceb5d0478b789798e819bde)\n" + expectedPrBody = "
\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesFixBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n
\n\n\n\n## 📦 Vulnerable Dependencies\n\n### ✍️ Summary\n\n
\n\n\n| SEVERITY | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | | package1:1.0.0 | 1.0.0
2.0.0 | CVE-2022-1234 |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableCriticalSeverity.png)
Critical | | package2:2.0.0 | 2.0.0
3.0.0 | CVE-2022-4321 |\n\n
\n\n## 🔬 Research Details\n\n
\n [ CVE-2022-1234 ] package1 1.0.0 \n
\n\n**Description:**\nsummary\n\n\n
\n\n\n
\n [ CVE-2022-4321 ] package2 2.0.0 \n
\n\n**Description:**\nsummary\n\n\n
\n\n\n---\n
\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n
\n\n[comment]: <> (Checksum: bec823edaceb5d0478b789798e819bde)\n" prTitle, prBody, err = cfp.preparePullRequestDetails(vulnerabilities...) assert.NoError(t, err) - assert.Equal(t, outputwriter.GetAggregatedPullRequestTitle(""), prTitle) + assert.Equal(t, cfp.gitManager.GenerateAggregatedPullRequestTitle([]coreutils.Technology{}), prTitle) assert.Equal(t, expectedPrBody, prBody) cfp.OutputWriter = &outputwriter.SimplifiedOutput{} - expectedPrBody = "**🚨 This automated pull request was created by Frogbot and fixes the below:**\n\n\n---\n## 📦 Vulnerable Dependencies\n---\n\n### ✍️ Summary \n\n\n| SEVERITY | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| High | | package1:1.0.0 | 1.0.0, 2.0.0 | CVE-2022-1234 |\n| Critical | | package2:2.0.0 | 2.0.0, 3.0.0 | CVE-2022-4321 |\n\n---\n### 👇 Details\n---\n\n\n#### [ CVE-2022-1234 ] package1 1.0.0\n\n\n**Description:**\nsummary\n\n\n#### [ CVE-2022-4321 ] package2 2.0.0\n\n\n**Description:**\nsummary\n\n\n---\n\n\n**Frogbot** also supports **Contextual Analysis, Secret Detection and IaC Vulnerabilities Scanning**. This features are included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system.\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n[comment]: <> (Checksum: bec823edaceb5d0478b789798e819bde)\n" + expectedPrBody = "**🚨 This automated pull request was created by Frogbot and fixes the below:**\n\n\n---\n## 📦 Vulnerable Dependencies\n---\n\n### ✍️ Summary\n\n\n| SEVERITY | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| High | | package1:1.0.0 | 1.0.0, 2.0.0 | CVE-2022-1234 |\n| Critical | | package2:2.0.0 | 2.0.0, 3.0.0 | CVE-2022-4321 |\n\n---\n## 🔬 Research Details\n---\n\n\n#### [ CVE-2022-1234 ] package1 1.0.0\n\n\n**Description:**\nsummary\n\n\n#### [ CVE-2022-4321 ] package2 2.0.0\n\n\n**Description:**\nsummary\n\n\n\n---\n**Frogbot** also supports **Contextual Analysis, Secret Detection and IaC Vulnerabilities Scanning**. This features are included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system.\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n[comment]: <> (Checksum: bec823edaceb5d0478b789798e819bde)\n" prTitle, prBody, err = cfp.preparePullRequestDetails(vulnerabilities...) assert.NoError(t, err) - assert.Equal(t, outputwriter.GetAggregatedPullRequestTitle(""), prTitle) + assert.Equal(t, cfp.gitManager.GenerateAggregatedPullRequestTitle([]coreutils.Technology{}), prTitle) assert.Equal(t, expectedPrBody, prBody) } diff --git a/schema/frogbot-schema.json b/schema/frogbot-schema.json index 1630b8ce2..c06dec49a 100644 --- a/schema/frogbot-schema.json +++ b/schema/frogbot-schema.json @@ -117,6 +117,22 @@ "description": "Handle vulnerabilities with fix versions only.", "title": "Handle vulnerabilities with fix versions only" }, + "allowedLicenses": { + "type": [ + "array", + "null" + ], + "description": "List of allowed package licenses.", + "title": "List of allowed package licenses", + "items": { + "type": "string", + "title": "Allowed Package Licenses", + "examples": [ + "MIT", + "Apache-2.0" + ] + } + }, "emailReceivers": { "type": [ "array", diff --git a/testdata/config/frogbot-config-test-params-merge.yml b/testdata/config/frogbot-config-test-params-merge.yml index 4db0d38e8..3d77e222d 100755 --- a/testdata/config/frogbot-config-test-params-merge.yml +++ b/testdata/config/frogbot-config-test-params-merge.yml @@ -10,6 +10,9 @@ includeAllVulnerabilities: true minSeverity: high fixableOnly: true + allowedLicenses: + - ISC + - MIT projects: - workingDirs: - a/b diff --git a/testdata/messages/novulnerabilities.md b/testdata/messages/novulnerabilities.md index 76264f7e3..51aa43540 100755 --- a/testdata/messages/novulnerabilities.md +++ b/testdata/messages/novulnerabilities.md @@ -5,6 +5,7 @@ +---
**Frogbot** also supports **Contextual Analysis, Secret Detection and IaC Vulnerabilities Scanning**. This features are included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system. diff --git a/testdata/messages/novulnerabilitiesMR.md b/testdata/messages/novulnerabilitiesMR.md index 709385936..2f719f82e 100755 --- a/testdata/messages/novulnerabilitiesMR.md +++ b/testdata/messages/novulnerabilitiesMR.md @@ -5,6 +5,7 @@
+---
**Frogbot** also supports **Contextual Analysis, Secret Detection and IaC Vulnerabilities Scanning**. This features are included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system. diff --git a/testdata/scanpullrequest/expectedResponse.json b/testdata/scanpullrequest/expectedResponse.json index 75f419f70..ded9c6bdf 100755 --- a/testdata/scanpullrequest/expectedResponse.json +++ b/testdata/scanpullrequest/expectedResponse.json @@ -1,3 +1,3 @@ { - "body": "\u003cdiv align='center'\u003e\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n\u003c/div\u003e\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n\u003cdiv align=\"center\"\u003e\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/notApplicableCritical.png)\u003cbr\u003eCritical | Not Applicable | minimist:1.2.5 | minimist:1.2.5 | [0.2.4]\u003cbr\u003e[1.2.6] | CVE-2021-44906 |\n\n\u003c/div\u003e\n\n## 👇 Details\n\n\n**Description:**\n[Minimist](https://github.com/substack/minimist) is a simple and very popular argument parser. It is used by more than 14 million by Mar 2022. This package developers stopped developing it since April 2020 and its community released a [newer version](https://github.com/meszaros-lajos-gyorgy/minimist-lite) supported by the community.\n\n\nAn incomplete fix for [CVE-2020-7598](https://nvd.nist.gov/vuln/detail/CVE-2020-7598) partially blocked prototype pollution attacks. Researchers discovered that it does not check for constructor functions which means they can be overridden. This behavior can be triggered easily when using it insecurely (which is the common usage). For example:\n```\nvar argv = parse(['--_.concat.constructor.prototype.y', '123']);\nt.equal((function(){}).foo, undefined);\nt.equal(argv.y, undefined);\n```\nIn this example, `prototype.y` is assigned with `123` which will be derived to every newly created object. \n\nThis vulnerability can be triggered when the attacker-controlled input is parsed using Minimist without any validation. As always with prototype pollution, the impact depends on the code that follows the attack, but denial of service is almost always guaranteed.\n**Remediation:**\n##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\n\n---\n\u003cdiv align=\"center\"\u003e\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n\u003c/div\u003e" + "body": "\u003cdiv align='center'\u003e\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n\u003c/div\u003e\n\n\n## 📦 Vulnerable Dependencies\n\n### ✍️ Summary\n\n\u003cdiv align=\"center\"\u003e\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/notApplicableCritical.png)\u003cbr\u003eCritical | Not Applicable | minimist:1.2.5 | minimist:1.2.5 | [0.2.4]\u003cbr\u003e[1.2.6] | CVE-2021-44906 |\n\n\u003c/div\u003e\n\n## 🔬 Research Details\n\n\n**Description:**\n[Minimist](https://github.com/substack/minimist) is a simple and very popular argument parser. It is used by more than 14 million by Mar 2022. This package developers stopped developing it since April 2020 and its community released a [newer version](https://github.com/meszaros-lajos-gyorgy/minimist-lite) supported by the community.\n\n\nAn incomplete fix for [CVE-2020-7598](https://nvd.nist.gov/vuln/detail/CVE-2020-7598) partially blocked prototype pollution attacks. Researchers discovered that it does not check for constructor functions which means they can be overridden. This behavior can be triggered easily when using it insecurely (which is the common usage). For example:\n```\nvar argv = parse(['--_.concat.constructor.prototype.y', '123']);\nt.equal((function(){}).foo, undefined);\nt.equal(argv.y, undefined);\n```\nIn this example, `prototype.y` is assigned with `123` which will be derived to every newly created object. \n\nThis vulnerability can be triggered when the attacker-controlled input is parsed using Minimist without any validation. As always with prototype pollution, the impact depends on the code that follows the attack, but denial of service is almost always guaranteed.\n**Remediation:**\n##### Development mitigations\n\nAdd the `Object.freeze(Object.prototype);` directive once at the beginning of your main JS source code file (ex. `index.js`), preferably after all your `require` directives. This will prevent any changes to the prototype object, thus completely negating prototype pollution attacks.\n\n\n---\n\u003cdiv align=\"center\"\u003e\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n\u003c/div\u003e" } \ No newline at end of file diff --git a/testdata/scanpullrequest/expectedResponseMultiDir.json b/testdata/scanpullrequest/expectedResponseMultiDir.json index 2c450de69..626ca5f06 100755 --- a/testdata/scanpullrequest/expectedResponseMultiDir.json +++ b/testdata/scanpullrequest/expectedResponseMultiDir.json @@ -1,3 +1,3 @@ { - "body": "\u003cdiv align='center'\u003e\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n\u003c/div\u003e\n\n\n## 📦 Vulnerable Dependencies \n\n### ✍️ Summary\n\n\u003cdiv align=\"center\"\u003e\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/notApplicableHigh.png)\u003cbr\u003e High | Not Applicable | minimatch:3.0.4 | minimatch:3.0.4 | [3.0.5] | CVE-2022-3517 |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)\u003cbr\u003e High | Undetermined | pyjwt:1.7.1 | pyjwt:1.7.1 | [2.4.0] | CVE-2022-29217 |\n\n\u003c/div\u003e\n\n## 👇 Details\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003cb\u003e[ CVE-2022-3517 ] minimatch 3.0.4\u003c/b\u003e \u003c/summary\u003e\n\u003cbr\u003e\n\n**Description:**\nA vulnerability was found in the minimatch package. This flaw allows a Regular Expression Denial of Service (ReDoS) when calling the braceExpand function with specific arguments, resulting in a Denial of Service.\n\n\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003cb\u003e[ CVE-2022-29217 ] pyjwt 1.7.1\u003c/b\u003e \u003c/summary\u003e\n\u003cbr\u003e\n\n**Description:**\n[PyJWT](https://pypi.org/project/PyJWT) is a Python implementation of the RFC 7519 standard (JSON Web Tokens). [JSON Web Tokens](https://jwt.io/) are an open, industry standard method for representing claims securely between two parties. A JWT comes with an inline signature that is meant to be verified by the receiving application. JWT supports multiple standard algorithms, and the algorithm itself is **specified in the JWT token itself**.\n\nThe PyJWT library uses the signature-verification algorithm that is specified in the JWT token (that is completely attacker-controlled), however - it requires the validating application to pass an `algorithms` kwarg that specifies the expected algorithms in order to avoid key confusion. Unfortunately - a non-default value `algorithms=jwt.algorithms.get_default_algorithms()` exists that allows all algorithms.\nThe PyJWT library also tries to mitigate key confusions in this case, by making sure that public keys are not used as an HMAC secret. For example, HMAC secrets that begin with `-----BEGIN PUBLIC KEY-----` are rejected when encoding a JWT.\n\nIt has been discovered that due to missing key-type checks, in cases where -\n1. The vulnerable application expects to receive a JWT signed with an Elliptic-Curve key (one of the algorithms `ES256`, `ES384`, `ES512`, `EdDSA`)\n2. The vulnerable application decodes the JWT token using the non-default kwarg `algorithms=jwt.algorithms.get_default_algorithms()` (or alternatively, `algorithms` contain both an HMAC-based algorithm and an EC-based algorithm)\n\nAn attacker can create an HMAC-signed (ex. `HS256`) JWT token, using the (well-known!) EC public key as the HMAC key. The validating application will accept this JWT token as a valid token.\n\nFor example, an application might have planned to validate an `EdDSA`-signed token that was generated as follows -\n```python\n# Making a good jwt token that should work by signing it with the private key\nencoded_good = jwt.encode({\"test\": 1234}, priv_key_bytes, algorithm=\"EdDSA\")\n```\nAn attacker in posession of the public key can generate an `HMAC`-signed token to confuse PyJWT - \n```python\n# Using HMAC with the public key to trick the receiver to think that the public key is a HMAC secret\nencoded_bad = jwt.encode({\"test\": 1234}, pub_key_bytes, algorithm=\"HS256\")\n```\n\nThe following vulnerable `decode` call will accept BOTH of the above tokens as valid - \n```\ndecoded = jwt.decode(encoded_good, pub_key_bytes, \nalgorithms=jwt.algorithms.get_default_algorithms())\n```\n**Remediation:**\n##### Development mitigations\n\nUse a specific algorithm instead of `jwt.algorithms.get_default_algorithms`.\nFor example, replace the following call - \n`jwt.decode(encoded_jwt, pub_key_bytes, algorithms=jwt.algorithms.get_default_algorithms())`\nWith -\n`jwt.decode(encoded_jwt, pub_key_bytes, algorithms=[\"ES256\"])`\n\n\n\u003c/details\u003e\n\n\n---\n\u003cdiv align=\"center\"\u003e\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n\u003c/div\u003e" + "body": "\u003cdiv align='center'\u003e\n\n[![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/vulnerabilitiesBannerPR.png)](https://github.com/jfrog/frogbot#readme)\n\n\u003c/div\u003e\n\n\n## 📦 Vulnerable Dependencies\n\n### ✍️ Summary\n\n\u003cdiv align=\"center\"\u003e\n\n| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: | \n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/notApplicableHigh.png)\u003cbr\u003e High | Not Applicable | minimatch:3.0.4 | minimatch:3.0.4 | [3.0.5] | CVE-2022-3517 |\n| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)\u003cbr\u003e High | Undetermined | pyjwt:1.7.1 | pyjwt:1.7.1 | [2.4.0] | CVE-2022-29217 |\n\n\u003c/div\u003e\n\n## 🔬 Research Details\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003cb\u003e[ CVE-2022-3517 ] minimatch 3.0.4\u003c/b\u003e \u003c/summary\u003e\n\u003cbr\u003e\n\n**Description:**\nA vulnerability was found in the minimatch package. This flaw allows a Regular Expression Denial of Service (ReDoS) when calling the braceExpand function with specific arguments, resulting in a Denial of Service.\n\n\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003cb\u003e[ CVE-2022-29217 ] pyjwt 1.7.1\u003c/b\u003e \u003c/summary\u003e\n\u003cbr\u003e\n\n**Description:**\n[PyJWT](https://pypi.org/project/PyJWT) is a Python implementation of the RFC 7519 standard (JSON Web Tokens). [JSON Web Tokens](https://jwt.io/) are an open, industry standard method for representing claims securely between two parties. A JWT comes with an inline signature that is meant to be verified by the receiving application. JWT supports multiple standard algorithms, and the algorithm itself is **specified in the JWT token itself**.\n\nThe PyJWT library uses the signature-verification algorithm that is specified in the JWT token (that is completely attacker-controlled), however - it requires the validating application to pass an `algorithms` kwarg that specifies the expected algorithms in order to avoid key confusion. Unfortunately - a non-default value `algorithms=jwt.algorithms.get_default_algorithms()` exists that allows all algorithms.\nThe PyJWT library also tries to mitigate key confusions in this case, by making sure that public keys are not used as an HMAC secret. For example, HMAC secrets that begin with `-----BEGIN PUBLIC KEY-----` are rejected when encoding a JWT.\n\nIt has been discovered that due to missing key-type checks, in cases where -\n1. The vulnerable application expects to receive a JWT signed with an Elliptic-Curve key (one of the algorithms `ES256`, `ES384`, `ES512`, `EdDSA`)\n2. The vulnerable application decodes the JWT token using the non-default kwarg `algorithms=jwt.algorithms.get_default_algorithms()` (or alternatively, `algorithms` contain both an HMAC-based algorithm and an EC-based algorithm)\n\nAn attacker can create an HMAC-signed (ex. `HS256`) JWT token, using the (well-known!) EC public key as the HMAC key. The validating application will accept this JWT token as a valid token.\n\nFor example, an application might have planned to validate an `EdDSA`-signed token that was generated as follows -\n```python\n# Making a good jwt token that should work by signing it with the private key\nencoded_good = jwt.encode({\"test\": 1234}, priv_key_bytes, algorithm=\"EdDSA\")\n```\nAn attacker in posession of the public key can generate an `HMAC`-signed token to confuse PyJWT - \n```python\n# Using HMAC with the public key to trick the receiver to think that the public key is a HMAC secret\nencoded_bad = jwt.encode({\"test\": 1234}, pub_key_bytes, algorithm=\"HS256\")\n```\n\nThe following vulnerable `decode` call will accept BOTH of the above tokens as valid - \n```\ndecoded = jwt.decode(encoded_good, pub_key_bytes, \nalgorithms=jwt.algorithms.get_default_algorithms())\n```\n**Remediation:**\n##### Development mitigations\n\nUse a specific algorithm instead of `jwt.algorithms.get_default_algorithms`.\nFor example, replace the following call - \n`jwt.decode(encoded_jwt, pub_key_bytes, algorithms=jwt.algorithms.get_default_algorithms())`\nWith -\n`jwt.decode(encoded_jwt, pub_key_bytes, algorithms=[\"ES256\"])`\n\n\n\u003c/details\u003e\n\n\n---\n\u003cdiv align=\"center\"\u003e\n\n[🐸 JFrog Frogbot](https://github.com/jfrog/frogbot#readme)\n\n\u003c/div\u003e" } \ No newline at end of file diff --git a/utils/consts.go b/utils/consts.go index 99d9195b0..7a9720a9b 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -52,6 +52,7 @@ const ( DepsRepoEnv = "JF_DEPS_REPO" MinSeverityEnv = "JF_MIN_SEVERITY" FixableOnlyEnv = "JF_FIXABLE_ONLY" + AllowedLicensesEnv = "JF_ALLOWED_LICENSES" WatchesDelimiter = "," // Email related environment variables @@ -81,10 +82,12 @@ const ( BranchHashPlaceHolder = "${BRANCH_NAME_HASH}" // Default naming templates - BranchNameTemplate = "frogbot-" + PackagePlaceHolder + "-" + BranchHashPlaceHolder - AggregatedBranchNameTemplate = "frogbot-update-" + BranchHashPlaceHolder + "-dependencies" - CommitMessageTemplate = "Upgrade " + PackagePlaceHolder + " to " + FixVersionPlaceHolder - PullRequestTitleTemplate = outputwriter.FrogbotTitlePrefix + " Update version of " + PackagePlaceHolder + " to " + FixVersionPlaceHolder + BranchNameTemplate = "frogbot-" + PackagePlaceHolder + "-" + BranchHashPlaceHolder + AggregatedBranchNameTemplate = "frogbot-update-" + BranchHashPlaceHolder + "-dependencies" + CommitMessageTemplate = "Upgrade " + PackagePlaceHolder + " to " + FixVersionPlaceHolder + PullRequestTitleTemplate = outputwriter.FrogbotTitlePrefix + " Update version of " + PackagePlaceHolder + " to " + FixVersionPlaceHolder + AggregatePullRequestTitleDefaultTemplate = outputwriter.FrogbotTitlePrefix + " Update %s dependencies" + AggregatePullRequestTitle = outputwriter.FrogbotTitlePrefix + " Update dependencies" // Frogbot Git author details showed in commits frogbotAuthorName = "JFrog-Frogbot" frogbotAuthorEmail = "eco-system+frogbot@jfrog.com" diff --git a/utils/depsutil.go b/utils/depsutil.go index 6e5fe1cea..7c8ae409f 100644 --- a/utils/depsutil.go +++ b/utils/depsutil.go @@ -19,10 +19,10 @@ import ( type resolveDependenciesFunc func(scanSetup *ScanDetails) ([]byte, error) var MapTechToResolvingFunc = map[string]resolveDependenciesFunc{ - coreutils.Npm.ToString(): resolveNpmDependencies, - coreutils.Yarn.ToString(): resolveYarnDependencies, - coreutils.Dotnet.ToString(): resolveDotnetDependencies, - coreutils.Nuget.ToString(): resolveDotnetDependencies, + coreutils.Npm.String(): resolveNpmDependencies, + coreutils.Yarn.String(): resolveYarnDependencies, + coreutils.Dotnet.String(): resolveDotnetDependencies, + coreutils.Nuget.String(): resolveDotnetDependencies, } const yarnV2Version = "2.0.0" @@ -30,28 +30,27 @@ const yarnV2Version = "2.0.0" func resolveNpmDependencies(scanSetup *ScanDetails) (output []byte, err error) { npmCmd := npm.NewNpmCommand(scanSetup.InstallCommandArgs[0], false).SetServerDetails(scanSetup.ServerDetails) if err = npmCmd.PreparePrerequisites(scanSetup.DepsRepo); err != nil { - return nil, err + return } if err = npmCmd.CreateTempNpmrc(); err != nil { - return nil, err + return } defer func() { restoreNpmrc := npmCmd.RestoreNpmrcFunc() - if err == nil { - err = restoreNpmrc() - } + err = errors.Join(err, restoreNpmrc()) }() - return exec.Command(coreutils.Npm.ToString(), scanSetup.InstallCommandArgs...).CombinedOutput() + output, err = exec.Command(coreutils.Npm.String(), scanSetup.InstallCommandArgs...).CombinedOutput() + return } func resolveYarnDependencies(scanSetup *ScanDetails) (output []byte, err error) { currWd, err := coreutils.GetWorkingDirectory() if err != nil { - return nil, err + return } yarnExecPath, err := exec.LookPath("yarn") if err != nil { - return nil, err + return } executableYarnVersion, err := biUtils.GetVersion(yarnExecPath, currWd) @@ -67,24 +66,28 @@ func resolveYarnDependencies(scanSetup *ScanDetails) (output []byte, err error) restoreYarnrcFunc, err := rtutils.BackupFile(filepath.Join(currWd, yarn.YarnrcFileName), yarn.YarnrcBackupFileName) if err != nil { - return nil, err + return } registry, repoAuthIdent, err := yarn.GetYarnAuthDetails(scanSetup.ServerDetails, scanSetup.DepsRepo) if err != nil { - return nil, yarn.RestoreConfigurationsAndError(nil, restoreYarnrcFunc, err) + err = errors.Join(err, restoreYarnrcFunc()) + return } backupEnvMap, err := yarn.ModifyYarnConfigurations(yarnExecPath, registry, repoAuthIdent) if err != nil { - return nil, yarn.RestoreConfigurationsAndError(backupEnvMap, restoreYarnrcFunc, err) + if len(backupEnvMap) > 0 { + err = errors.Join(err, yarn.RestoreConfigurationsFromBackup(backupEnvMap, restoreYarnrcFunc)) + } else { + err = errors.Join(err, restoreYarnrcFunc()) + } + return } defer func() { - e := yarn.RestoreConfigurationsFromBackup(backupEnvMap, restoreYarnrcFunc) - if err == nil { - err = e - } + err = errors.Join(err, yarn.RestoreConfigurationsFromBackup(backupEnvMap, restoreYarnrcFunc)) }() - return nil, build.RunYarnCommand(yarnExecPath, currWd, scanSetup.InstallCommandArgs...) + err = build.RunYarnCommand(yarnExecPath, currWd, scanSetup.InstallCommandArgs...) + return } func resolveDotnetDependencies(scanSetup *ScanDetails) (output []byte, err error) { @@ -93,10 +96,7 @@ func resolveDotnetDependencies(scanSetup *ScanDetails) (output []byte, err error return } defer func() { - e := fileutils.RemoveTempDir(wd) - if err == nil { - err = e - } + err = errors.Join(err, fileutils.RemoveTempDir(wd)) }() configFile, err := dotnet.InitNewConfig(wd, scanSetup.DepsRepo, scanSetup.ServerDetails, false) if err != nil { @@ -105,5 +105,6 @@ func resolveDotnetDependencies(scanSetup *ScanDetails) (output []byte, err error toolType := dotnetutils.ConvertNameToToolType(scanSetup.InstallCommandName) args := scanSetup.InstallCommandArgs args = append(args, toolType.GetTypeFlagPrefix()+"configfile", configFile.Name()) - return exec.Command(toolType.String(), args...).CombinedOutput() + output, err = exec.Command(toolType.String(), args...).CombinedOutput() + return } diff --git a/utils/email.go b/utils/email.go index 0e437dc13..286b3356f 100644 --- a/utils/email.go +++ b/utils/email.go @@ -25,12 +25,18 @@ type SecretsEmailDetails struct { EmailDetails } -func NewSecretsEmailDetails(gitClient vcsclient.VcsClient, gitProvider vcsutils.VcsProvider, - repoOwner, repoName, branch, pullRequestLink string, - detectedSecrets []formats.SourceCodeRow, emailDetails EmailDetails) *SecretsEmailDetails { - return &SecretsEmailDetails{gitClient: gitClient, gitProvider: gitProvider, - repoOwner: repoOwner, repoName: repoName, branch: branch, pullRequestLink: pullRequestLink, - detectedSecrets: detectedSecrets, EmailDetails: emailDetails} +func NewSecretsEmailDetails(gitClient vcsclient.VcsClient, repoConfig *Repository, secrets []formats.SourceCodeRow) *SecretsEmailDetails { + secretsEmailDetails := &SecretsEmailDetails{ + gitClient: gitClient, + EmailDetails: repoConfig.EmailDetails, + gitProvider: repoConfig.GitProvider, + repoOwner: repoConfig.PullRequestDetails.Source.Owner, + repoName: repoConfig.PullRequestDetails.Source.Repository, + branch: repoConfig.PullRequestDetails.Source.Name, + detectedSecrets: secrets, + pullRequestLink: repoConfig.PullRequestDetails.URL, + } + return secretsEmailDetails } func AlertSecretsExposed(secretsDetails *SecretsEmailDetails) (err error) { diff --git a/utils/email_test.go b/utils/email_test.go index 3dcc360f2..a410dd05c 100644 --- a/utils/email_test.go +++ b/utils/email_test.go @@ -13,12 +13,15 @@ import ( func TestGetSecretsEmailContent(t *testing.T) { secrets := []formats.SourceCodeRow{ - {Severity: "High", + { + SeverityDetails: formats.SeverityDetails{Severity: "High"}, Location: formats.Location{ File: "/config.yaml", StartLine: 12, StartColumn: 30, Snippet: "pass*****"}, }, - {Severity: "Medium", Location: formats.Location{ - File: "/server-conf.json", StartLine: 15, StartColumn: 20, Snippet: "pass*****"}}, + { + SeverityDetails: formats.SeverityDetails{Severity: "Medium"}, + Location: formats.Location{ + File: "/server-conf.json", StartLine: 15, StartColumn: 20, Snippet: "pass*****"}}, } // Test for results including the "Pull Request" keyword expected := "\n\n\n\n Frogbot Secret Detection\n \n\n\n\t
\n\t\tThe following potential exposed secrets in your pull request have been detected by Frogbot\n\t\t
\n\t\t\n \n \n \n \n \n \n \n \n \n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n \n
FILELINE:COLUMNSECRET
/config.yaml 12:30 pass*****
/server-conf.json 15:20 pass*****
\n\t\t
\n\t\tNOTE: If you'd like Frogbot to ignore the lines with the potential secrets, add a comment that includes the jfrog-ignore keyword above the lines with the secrets.\t\n\t\t
\n\t
\n\n" diff --git a/utils/git.go b/utils/git.go index 77b3d711c..835f79c09 100644 --- a/utils/git.go +++ b/utils/git.go @@ -7,11 +7,11 @@ import ( "github.com/go-git/go-git/v5/plumbing/protocol/packp/capability" "github.com/go-git/go-git/v5/plumbing/transport" "github.com/go-git/go-git/v5/plumbing/transport/client" - "github.com/jfrog/frogbot/utils/outputwriter" "github.com/jfrog/froggit-go/vcsutils" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "net/http" + "regexp" "strings" "time" @@ -29,6 +29,10 @@ const ( // Timout is seconds for the git operations performed by the go-git client. goGitTimeoutSeconds = 120 + + // Separators used to convert technologies array into string + fixBranchTechSeparator = "-" + pullRequestTitleTechSeparator = "," ) type GitManager struct { @@ -323,10 +327,11 @@ func (gm *GitManager) GenerateCommitMessage(impactedPackage string, fixVersion s return formatStringWithPlaceHolders(template, impactedPackage, fixVersion, "", true) } -func (gm *GitManager) GenerateAggregatedCommitMessage(tech coreutils.Technology) string { +func (gm *GitManager) GenerateAggregatedCommitMessage(tech []coreutils.Technology) string { template := gm.customTemplates.commitMessageTemplate if template == "" { - template = outputwriter.GetAggregatedPullRequestTitle(tech) + // In aggregated mode, commit message and PR title are the same. + template = gm.GenerateAggregatedPullRequestTitle(tech) } return formatStringWithPlaceHolders(template, "", "", "", true) } @@ -372,14 +377,32 @@ func (gm *GitManager) GeneratePullRequestTitle(impactedPackage string, version s return formatStringWithPlaceHolders(template, impactedPackage, version, "", true) } +func (gm *GitManager) GenerateAggregatedPullRequestTitle(tech []coreutils.Technology) string { + template := gm.getPullRequestTitleTemplate(tech) + // If no technologies are provided, return the template as-is + if len(tech) == 0 { + return normalizeWhitespaces(strings.ReplaceAll(template, "%s", "")) + } + return fmt.Sprintf(template, techArrayToString(tech, pullRequestTitleTechSeparator)) +} + +func (gm *GitManager) getPullRequestTitleTemplate(tech []coreutils.Technology) string { + // Check if a custom template is available + if customTemplate := gm.customTemplates.pullRequestTitleTemplate; customTemplate != "" { + return parseCustomTemplate(customTemplate, tech) + } + // If no custom template, use the default template + return AggregatePullRequestTitleDefaultTemplate +} + // GenerateAggregatedFixBranchName Generating a consistent branch name to enable branch updates // and to ensure that there is only one Frogbot branch in aggregated mode. -func (gm *GitManager) GenerateAggregatedFixBranchName(tech coreutils.Technology) (fixBranchName string, err error) { +func (gm *GitManager) GenerateAggregatedFixBranchName(tech []coreutils.Technology) (fixBranchName string, err error) { branchFormat := gm.customTemplates.branchNameTemplate if branchFormat == "" { branchFormat = AggregatedBranchNameTemplate } - return formatStringWithPlaceHolders(branchFormat, "", "", tech.ToString(), false), nil + return formatStringWithPlaceHolders(branchFormat, "", "", techArrayToString(tech, fixBranchTechSeparator), false), nil } // dryRunClone clones an existing repository from our testdata folder into the destination folder for testing purposes. @@ -431,7 +454,22 @@ func setGoGitCustomClient() { customClient := &http.Client{ Timeout: goGitTimeoutSeconds * time.Second, } - client.InstallProtocol("http", githttp.NewClient(customClient)) client.InstallProtocol("https", githttp.NewClient(customClient)) } + +// Clean user template from input strings and add suffix. +func parseCustomTemplate(customTemplate string, tech []coreutils.Technology) string { + trimSpace := strings.TrimSpace(customTemplate) + // Find any input format strings + re := regexp.MustCompile(`%[sdvTtqwxXbcdoUxfeEgGp]`) + // Replace all matching substrings with an empty string + result := re.ReplaceAllString(trimSpace, "") + // Remove any middle spaces + result = strings.Join(strings.Fields(result), " ") + var suffix string + if len(tech) > 0 { + suffix = " - %s Dependencies" + } + return normalizeWhitespaces(result) + suffix +} diff --git a/utils/git_test.go b/utils/git_test.go index 8ff6d6aa4..45f513791 100644 --- a/utils/git_test.go +++ b/utils/git_test.go @@ -5,7 +5,6 @@ import ( "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing/object" - "github.com/jfrog/frogbot/utils/outputwriter" "github.com/jfrog/froggit-go/vcsutils" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" @@ -133,19 +132,19 @@ func TestGitManager_GenerateAggregatedFixBranchName(t *testing.T) { desc string }{ { - expected: "frogbot-update-go-dependencies", + expected: "frogbot-update-Go-dependencies", desc: "No template", gitManager: GitManager{}, }, { - expected: "[feature]-go", + expected: "[feature]-Go", desc: "Custom template hash only", gitManager: GitManager{customTemplates: CustomTemplates{branchNameTemplate: "[feature]-${BRANCH_NAME_HASH}"}}, }, } for _, test := range testCases { t.Run(test.desc, func(t *testing.T) { - titleOutput, err := test.gitManager.GenerateAggregatedFixBranchName(coreutils.Go) + titleOutput, err := test.gitManager.GenerateAggregatedFixBranchName([]coreutils.Technology{coreutils.Go}) assert.NoError(t, err) assert.Equal(t, test.expected, titleOutput) }) @@ -157,12 +156,12 @@ func TestGitManager_GenerateAggregatedCommitMessage(t *testing.T) { gitManager GitManager expected string }{ - {gitManager: GitManager{}, expected: outputwriter.GetAggregatedPullRequestTitle(coreutils.Pipenv)}, + {gitManager: GitManager{}, expected: "[🐸 Frogbot] Update Pipenv dependencies"}, {gitManager: GitManager{customTemplates: CustomTemplates{commitMessageTemplate: "custom_template"}}, expected: "custom_template"}, } for _, test := range testCases { t.Run(test.expected, func(t *testing.T) { - commit := test.gitManager.GenerateAggregatedCommitMessage(coreutils.Pipenv) + commit := test.gitManager.GenerateAggregatedCommitMessage([]coreutils.Technology{coreutils.Pipenv}) assert.Equal(t, commit, test.expected) }) } @@ -295,3 +294,32 @@ func TestGitManager_SetRemoteGitUrl(t *testing.T) { }) } } + +func TestGetAggregatedPullRequestTitle(t *testing.T) { + defaultGm := GitManager{} + testsCases := []struct { + tech []coreutils.Technology + gm GitManager + expected string + }{ + {gm: defaultGm, tech: []coreutils.Technology{}, expected: "[🐸 Frogbot] Update dependencies"}, + {gm: defaultGm, tech: []coreutils.Technology{coreutils.Maven}, expected: "[🐸 Frogbot] Update Maven dependencies"}, + {gm: defaultGm, tech: []coreutils.Technology{coreutils.Gradle}, expected: "[🐸 Frogbot] Update Gradle dependencies"}, + {gm: defaultGm, tech: []coreutils.Technology{coreutils.Npm}, expected: "[🐸 Frogbot] Update npm dependencies"}, + {gm: defaultGm, tech: []coreutils.Technology{coreutils.Yarn}, expected: "[🐸 Frogbot] Update Yarn dependencies"}, + {gm: GitManager{customTemplates: CustomTemplates{pullRequestTitleTemplate: "[Dependencies] My template "}}, tech: []coreutils.Technology{coreutils.Yarn}, expected: "[Dependencies] My template - Yarn Dependencies"}, + {gm: GitManager{customTemplates: CustomTemplates{pullRequestTitleTemplate: ""}}, tech: []coreutils.Technology{coreutils.Yarn}, expected: "[🐸 Frogbot] Update Yarn dependencies"}, + {gm: GitManager{customTemplates: CustomTemplates{pullRequestTitleTemplate: "[Feature] %s hello"}}, tech: []coreutils.Technology{coreutils.Yarn}, expected: "[Feature] hello - Yarn Dependencies"}, + {gm: GitManager{customTemplates: CustomTemplates{pullRequestTitleTemplate: "[Feature] %s %d hello"}}, tech: []coreutils.Technology{coreutils.Yarn}, expected: "[Feature] hello - Yarn Dependencies"}, + {gm: GitManager{customTemplates: CustomTemplates{pullRequestTitleTemplate: "[Feature] %s %d hello"}}, tech: []coreutils.Technology{coreutils.Yarn}, expected: "[Feature] hello - Yarn Dependencies"}, + {gm: GitManager{customTemplates: CustomTemplates{pullRequestTitleTemplate: "[Feature] %s %f hello"}}, tech: []coreutils.Technology{coreutils.Yarn, coreutils.Go}, expected: "[Feature] hello - Yarn,Go Dependencies"}, + {gm: GitManager{customTemplates: CustomTemplates{pullRequestTitleTemplate: "[Feature] %s %d hello"}}, tech: []coreutils.Technology{coreutils.Yarn, coreutils.Go, coreutils.Npm}, expected: "[Feature] hello - Yarn,Go,npm Dependencies"}, + {gm: GitManager{customTemplates: CustomTemplates{pullRequestTitleTemplate: "[Feature] %s %d hello"}}, tech: []coreutils.Technology{}, expected: "[Feature] hello"}, + } + for _, test := range testsCases { + t.Run(test.expected, func(t *testing.T) { + title := test.gm.GenerateAggregatedPullRequestTitle(test.tech) + assert.Equal(t, test.expected, title) + }) + } +} diff --git a/utils/issuescollection.go b/utils/issuescollection.go new file mode 100644 index 000000000..24a9ded9a --- /dev/null +++ b/utils/issuescollection.go @@ -0,0 +1,56 @@ +package utils + +import "github.com/jfrog/jfrog-cli-core/v2/xray/formats" + +type IssuesCollection struct { + Vulnerabilities []formats.VulnerabilityOrViolationRow + Iacs []formats.SourceCodeRow + Secrets []formats.SourceCodeRow + Sast []formats.SourceCodeRow + Licenses []formats.LicenseRow +} + +func (ic *IssuesCollection) VulnerabilitiesExists() bool { + return len(ic.Vulnerabilities) > 0 +} + +func (ic *IssuesCollection) IacExists() bool { + return len(ic.Iacs) > 0 +} + +func (ic *IssuesCollection) LicensesExists() bool { + return len(ic.Licenses) > 0 +} + +func (ic *IssuesCollection) SecretsExists() bool { + return len(ic.Secrets) > 0 +} + +func (ic *IssuesCollection) SastExists() bool { + return len(ic.Sast) > 0 +} + +func (ic *IssuesCollection) IssuesExists() bool { + return ic.VulnerabilitiesExists() || ic.IacExists() || ic.LicensesExists() || ic.SastExists() +} + +func (ic *IssuesCollection) Append(issues *IssuesCollection) { + if issues == nil { + return + } + if len(issues.Vulnerabilities) > 0 { + ic.Vulnerabilities = append(ic.Vulnerabilities, issues.Vulnerabilities...) + } + if len(issues.Secrets) > 0 { + ic.Secrets = append(ic.Secrets, issues.Secrets...) + } + if len(issues.Sast) > 0 { + ic.Sast = append(ic.Sast, issues.Sast...) + } + if len(issues.Iacs) > 0 { + ic.Iacs = append(ic.Iacs, issues.Iacs...) + } + if len(issues.Licenses) > 0 { + ic.Licenses = append(ic.Licenses, issues.Licenses...) + } +} diff --git a/utils/outputwriter/outputwriter.go b/utils/outputwriter/outputwriter.go index a9f68b561..cb9eb1955 100644 --- a/utils/outputwriter/outputwriter.go +++ b/utils/outputwriter/outputwriter.go @@ -5,7 +5,6 @@ import ( "strings" "github.com/jfrog/froggit-go/vcsutils" - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-core/v2/xray/formats" xrayutils "github.com/jfrog/jfrog-cli-core/v2/xray/utils" ) @@ -16,6 +15,13 @@ const ( vulnerabilitiesTableHeader = "\n| SEVERITY | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: |" vulnerabilitiesTableHeaderWithContextualAnalysis = "| SEVERITY | CONTEXTUAL ANALYSIS | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | FIXED VERSIONS | CVES |\n| :---------------------: | :----------------------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | :---------------------------------: |" iacTableHeader = "\n| SEVERITY | FILE | LINE:COLUMN | FINDING |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: |" + vulnerableDependenciesTitle = "## 📦 Vulnerable Dependencies" + summaryTitle = "### ✍️ Summary" + researchDetailsTitle = "## 🔬 Research Details" + iacTitle = "## 🛠️ Infrastructure as Code" + licenseTitle = "## ⚖️ Violated Licenses" + contextualAnalysisTitle = "## 📦🔍 Contextual Analysis CVE Vulnerability\n" + licenseTableHeader = "\n| LICENSE | DIRECT DEPENDENCIES | IMPACTED DEPENDENCY | \n| :---------------------: | :----------------------------------: | :-----------------------------------: |" SecretsEmailCSS = `body { font-family: Arial, sans-serif; background-color: #f5f5f5; @@ -99,6 +105,7 @@ type OutputWriter interface { NoVulnerabilitiesTitle() string VulnerabilitiesTitle(isComment bool) string VulnerabilitiesContent(vulnerabilities []formats.VulnerabilityOrViolationRow) string + LicensesContent(licenses []formats.LicenseRow) string IacTableContent(iacRows []formats.SourceCodeRow) string Footer() string Separator() string @@ -126,7 +133,7 @@ func GetCompatibleOutputWriter(provider vcsutils.VcsProvider) OutputWriter { func createVulnerabilityDescription(vulnerability *formats.VulnerabilityOrViolationRow) string { var descriptionBuilder strings.Builder vulnResearch := vulnerability.JfrogResearchInformation - if vulnerability.JfrogResearchInformation == nil { + if vulnResearch == nil { vulnResearch = &formats.JfrogResearchInformation{Details: vulnerability.Summary} } @@ -151,6 +158,20 @@ func getVulnerabilitiesTableContent(vulnerabilities []formats.VulnerabilityOrVio return tableContent } +func getLicensesTableContent(licenses []formats.LicenseRow, writer OutputWriter) string { + var tableContent strings.Builder + for _, license := range licenses { + var directDependenciesBuilder strings.Builder + for _, component := range license.Components { + directDependenciesBuilder.WriteString(fmt.Sprintf("%s %s%s", component.Name, component.Version, writer.Separator())) + } + directDependencies := strings.TrimSuffix(directDependenciesBuilder.String(), writer.Separator()) + impactedDependency := fmt.Sprintf("%s %s", license.ImpactedDependencyName, license.ImpactedDependencyVersion) + tableContent.WriteString(fmt.Sprintf("\n| %s | %s | %s |", license.LicenseKey, directDependencies, impactedDependency)) + } + return tableContent.String() +} + func getIacTableContent(iacRows []formats.SourceCodeRow, writer OutputWriter) string { var tableContent string for _, iac := range iacRows { @@ -193,13 +214,6 @@ at %s (line %d) location.StartLine) } -func GetAggregatedPullRequestTitle(tech coreutils.Technology) string { - if tech.ToString() == "" { - return FrogbotTitlePrefix + " Update dependencies" - } - return fmt.Sprintf("%s Update %s dependencies", FrogbotTitlePrefix, tech.ToFormal()) -} - func getVulnerabilitiesTableHeader(showCaColumn bool) string { if showCaColumn { return vulnerabilitiesTableHeaderWithContextualAnalysis diff --git a/utils/outputwriter/outputwriter_test.go b/utils/outputwriter/outputwriter_test.go index 49864275d..2f3ccb8de 100644 --- a/utils/outputwriter/outputwriter_test.go +++ b/utils/outputwriter/outputwriter_test.go @@ -1,25 +1,64 @@ package outputwriter import ( - "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" + "github.com/jfrog/jfrog-cli-core/v2/xray/formats" "github.com/stretchr/testify/assert" "testing" ) -func TestGetAggregatedPullRequestTitle(t *testing.T) { - tests := []struct { - tech coreutils.Technology - expected string - }{ - {tech: "", expected: "[🐸 Frogbot] Update dependencies"}, - {tech: coreutils.Maven, expected: "[🐸 Frogbot] Update Maven dependencies"}, - {tech: coreutils.Gradle, expected: "[🐸 Frogbot] Update Gradle dependencies"}, - {tech: coreutils.Npm, expected: "[🐸 Frogbot] Update npm dependencies"}, - {tech: coreutils.Yarn, expected: "[🐸 Frogbot] Update Yarn dependencies"}, +func TestMarkdownComment(t *testing.T) { + text := "" + result := MarkdownComment(text) + expected := "\n\n[comment]: <> ()\n" + assert.Equal(t, expected, result) + + text = "This is a comment" + result = MarkdownComment(text) + expected = "\n\n[comment]: <> (This is a comment)\n" + assert.Equal(t, expected, result) +} + +func testGetLicensesTableContent(t *testing.T, writer OutputWriter) { + licenses := []formats.LicenseRow{} + result := getLicensesTableContent(licenses, writer) + expected := "" + assert.Equal(t, expected, result) + + // Single license with components + licenses = []formats.LicenseRow{ + { + LicenseKey: "License1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + Components: []formats.ComponentRow{{Name: "Comp1", Version: "1.0"}}, + ImpactedDependencyName: "Dep1", + ImpactedDependencyVersion: "2.0", + }, + }, } + result = getLicensesTableContent(licenses, writer) + expected = "\n| License1 | Comp1 1.0 | Dep1 2.0 |" + assert.Equal(t, expected, result) - for _, test := range tests { - title := GetAggregatedPullRequestTitle(test.tech) - assert.Equal(t, test.expected, title) + // Test case 3: Multiple licenses with components + licenses = []formats.LicenseRow{ + { + LicenseKey: "License1", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + Components: []formats.ComponentRow{{Name: "Comp1", Version: "1.0"}}, + ImpactedDependencyName: "Dep1", + ImpactedDependencyVersion: "2.0", + }, + }, + { + LicenseKey: "License2", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + Components: []formats.ComponentRow{{Name: "Comp2", Version: "2.0"}}, + ImpactedDependencyName: "Dep2", + ImpactedDependencyVersion: "3.0", + }, + }, } + result = getLicensesTableContent(licenses, writer) + expected = "\n| License1 | Comp1 1.0 | Dep1 2.0 |\n| License2 | Comp2 2.0 | Dep2 3.0 |" + assert.Equal(t, expected, result) } diff --git a/utils/outputwriter/simplifiedoutput.go b/utils/outputwriter/simplifiedoutput.go index 00ee05536..b89779323 100644 --- a/utils/outputwriter/simplifiedoutput.go +++ b/utils/outputwriter/simplifiedoutput.go @@ -83,20 +83,24 @@ func (smo *SimplifiedOutput) VulnerabilitiesContent(vulnerabilities []formats.Vu // Write summary table part contentBuilder.WriteString(fmt.Sprintf(` --- -## 📦 Vulnerable Dependencies +%s --- -### ✍️ Summary +%s %s %s --- -### 👇 Details +%s --- `, + + vulnerableDependenciesTitle, + summaryTitle, getVulnerabilitiesTableHeader(smo.showCaColumn), - getVulnerabilitiesTableContent(vulnerabilities, smo))) + getVulnerabilitiesTableContent(vulnerabilities, smo), + researchDetailsTitle)) for i := range vulnerabilities { contentBuilder.WriteString(fmt.Sprintf(` #### %s%s %s @@ -146,16 +150,18 @@ func (smo *SimplifiedOutput) ApplicableCveReviewContent(severity, finding, fullD func (smo *SimplifiedOutput) IacReviewContent(severity, finding, fullDetails string) string { return fmt.Sprintf(` -## 🛠️ Infrastructure as Code (Iac) Vulnerability - %s -### 👇 Details +%s + +%s %s `, + iacTitle, GetJasMarkdownDescription(smo.FormattedSeverity(severity, "Applicable"), finding), + researchDetailsTitle, fullDetails) } @@ -207,17 +213,37 @@ Vulnerable data flow analysis result: return contentBuilder.String() } +func (smo *SimplifiedOutput) LicensesContent(licenses []formats.LicenseRow) string { + if len(licenses) == 0 { + return "" + } + + return fmt.Sprintf(` +--- +%s +--- + +%s +%s + +`, + licenseTitle, + licenseTableHeader, + getLicensesTableContent(licenses, smo)) +} + func (smo *SimplifiedOutput) IacTableContent(iacRows []formats.SourceCodeRow) string { if len(iacRows) == 0 { return "" } return fmt.Sprintf(` -## 🛠️ Infrastructure as Code +%s %s %s `, + iacTitle, iacTableHeader, getIacTableContent(iacRows, smo)) } @@ -237,7 +263,7 @@ func (smo *SimplifiedOutput) FormattedSeverity(severity, _ string) string { func (smo *SimplifiedOutput) UntitledForJasMsg() string { msg := "" if !smo.entitledForJas { - msg = "\n\n**Frogbot** also supports **Contextual Analysis, Secret Detection and IaC Vulnerabilities Scanning**. This features are included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system.\n" + msg = "\n\n---\n**Frogbot** also supports **Contextual Analysis, Secret Detection and IaC Vulnerabilities Scanning**. This features are included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system.\n" } return msg } diff --git a/utils/outputwriter/simplifiedoutput_test.go b/utils/outputwriter/simplifiedoutput_test.go index 6614335c7..c34bea018 100644 --- a/utils/outputwriter/simplifiedoutput_test.go +++ b/utils/outputwriter/simplifiedoutput_test.go @@ -5,6 +5,7 @@ import ( "github.com/jfrog/froggit-go/vcsutils" "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" "github.com/jfrog/jfrog-cli-core/v2/xray/formats" + "github.com/jfrog/jfrog-cli-core/v2/xray/utils" "github.com/stretchr/testify/assert" "testing" ) @@ -21,13 +22,15 @@ func TestSimplifiedOutput_VulnerabilitiesTableRow(t *testing.T) { { name: "Single CVE and one direct dependency", vulnerability: formats.VulnerabilityOrViolationRow{ - Severity: "High", - Components: []formats.ComponentRow{ - {Name: "dep1", Version: "1.0.0"}, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "impacted_dep", + ImpactedDependencyVersion: "2.0.0", + Components: []formats.ComponentRow{ + {Name: "dep1", Version: "1.0.0"}, + }, }, - ImpactedDependencyName: "impacted_dep", - ImpactedDependencyVersion: "2.0.0", - FixedVersions: []string{"3.0.0"}, + FixedVersions: []string{"3.0.0"}, Cves: []formats.CveRow{ {Id: "CVE-2022-0001"}, }, @@ -38,28 +41,32 @@ func TestSimplifiedOutput_VulnerabilitiesTableRow(t *testing.T) { { name: "No CVE and multiple direct dependencies", vulnerability: formats.VulnerabilityOrViolationRow{ - Severity: "Low", - Components: []formats.ComponentRow{ - {Name: "dep1", Version: "1.0.0"}, - {Name: "dep2", Version: "2.0.0"}, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "Low"}, + ImpactedDependencyName: "impacted_dep", + ImpactedDependencyVersion: "3.0.0", + Components: []formats.ComponentRow{ + {Name: "dep1", Version: "1.0.0"}, + {Name: "dep2", Version: "2.0.0"}, + }, }, - ImpactedDependencyName: "impacted_dep", - ImpactedDependencyVersion: "3.0.0", - FixedVersions: []string{"4.0.0", "4.1.0", "4.2.0", "5.0.0"}, - Cves: []formats.CveRow{}, - Technology: coreutils.Dotnet, + FixedVersions: []string{"4.0.0", "4.1.0", "4.2.0", "5.0.0"}, + Cves: []formats.CveRow{}, + Technology: coreutils.Dotnet, }, expectedOutput: "| Low | dep1:1.0.0 | impacted_dep:3.0.0 | 4.0.0, 4.1.0, 4.2.0, 5.0.0 | - |\n| | dep2:2.0.0 | | |", }, { name: "Multiple CVEs", vulnerability: formats.VulnerabilityOrViolationRow{ - Severity: "Critical", - Components: []formats.ComponentRow{{Name: "direct", Version: "1.0.2"}}, - Applicable: "Applicable", - ImpactedDependencyName: "impacted_dep", - ImpactedDependencyVersion: "4.0.0", - FixedVersions: []string{"5.0.0", "6.0.0"}, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "Critical"}, + ImpactedDependencyName: "impacted_dep", + ImpactedDependencyVersion: "4.0.0", + Components: []formats.ComponentRow{{Name: "direct", Version: "1.0.2"}}, + }, + Applicable: "Applicable", + FixedVersions: []string{"5.0.0", "6.0.0"}, Cves: []formats.CveRow{ {Id: "CVE-2022-0002"}, {Id: "CVE-2022-0003"}, @@ -119,20 +126,24 @@ func TestSimplifiedOutput_VulnerabilitiesContent(t *testing.T) { // Create some sample vulnerabilitiesRows for testing vulnerabilitiesRows := []formats.VulnerabilityOrViolationRow{ { - Severity: "Critical", - ImpactedDependencyName: "Dependency1", - Components: []formats.ComponentRow{{Name: "Direct1", Version: "1.0.0"}, {Name: "Direct2", Version: "2.0.0"}}, - FixedVersions: []string{"2.2.3"}, - Cves: []formats.CveRow{{Id: "CVE-2023-1234"}}, - ImpactedDependencyVersion: "1.0.0", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "Critical"}, + ImpactedDependencyName: "Dependency1", + ImpactedDependencyVersion: "1.0.0", + Components: []formats.ComponentRow{{Name: "Direct1", Version: "1.0.0"}, {Name: "Direct2", Version: "2.0.0"}}, + }, + FixedVersions: []string{"2.2.3"}, + Cves: []formats.CveRow{{Id: "CVE-2023-1234"}}, }, { - Severity: "High", - Components: []formats.ComponentRow{{Name: "Direct1", Version: "1.0.0"}, {Name: "Direct2", Version: "2.0.0"}}, - ImpactedDependencyName: "Dependency2", - FixedVersions: []string{"2.2.3"}, - Cves: []formats.CveRow{{Id: "CVE-2023-1234"}}, - ImpactedDependencyVersion: "2.0.0", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "Dependency2", + ImpactedDependencyVersion: "2.0.0", + Components: []formats.ComponentRow{{Name: "Direct1", Version: "1.0.0"}, {Name: "Direct2", Version: "2.0.0"}}, + }, + FixedVersions: []string{"2.2.3"}, + Cves: []formats.CveRow{{Id: "CVE-2023-1234"}}, }, } @@ -142,12 +153,12 @@ func TestSimplifiedOutput_VulnerabilitiesContent(t *testing.T) { ## 📦 Vulnerable Dependencies --- -### ✍️ Summary +### ✍️ Summary %s %s --- -### 👇 Details +## 🔬 Research Details --- @@ -186,24 +197,28 @@ func TestSimplifiedOutput_ContentWithContextualAnalysis(t *testing.T) { vulnerabilitiesRows := []formats.VulnerabilityOrViolationRow{ { - ImpactedDependencyName: "Dependency1", - ImpactedDependencyVersion: "1.0.0", - Severity: "High", - FixedVersions: []string{"2.2.3"}, - Components: []formats.ComponentRow{{Name: "Direct1", Version: "1.0.0"}, {Name: "Direct2", Version: "2.0.0"}}, - Cves: []formats.CveRow{{Id: "CVE-2023-1234"}}, - Applicable: "Applicable", - Technology: coreutils.Npm, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "Dependency1", + ImpactedDependencyVersion: "1.0.0", + Components: []formats.ComponentRow{{Name: "Direct1", Version: "1.0.0"}, {Name: "Direct2", Version: "2.0.0"}}, + }, + FixedVersions: []string{"2.2.3"}, + Cves: []formats.CveRow{{Id: "CVE-2023-1234"}}, + Applicable: utils.Applicable.String(), + Technology: coreutils.Npm, }, { - ImpactedDependencyName: "Dependency2", - ImpactedDependencyVersion: "2.0.0", - Severity: "Low", - Components: []formats.ComponentRow{{Name: "Direct1", Version: "1.0.0"}, {Name: "Direct2", Version: "2.0.0"}}, - FixedVersions: []string{"2.2.3"}, - Cves: []formats.CveRow{{Id: "CVE-2024-1234"}}, - Applicable: "Not Applicable", - Technology: coreutils.Poetry, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "Low"}, + ImpactedDependencyName: "Dependency2", + ImpactedDependencyVersion: "2.0.0", + Components: []formats.ComponentRow{{Name: "Direct1", Version: "1.0.0"}, {Name: "Direct2", Version: "2.0.0"}}, + }, + FixedVersions: []string{"2.2.3"}, + Cves: []formats.CveRow{{Id: "CVE-2024-1234"}}, + Applicable: "Not Applicable", + Technology: coreutils.Poetry, }, } @@ -212,12 +227,12 @@ func TestSimplifiedOutput_ContentWithContextualAnalysis(t *testing.T) { ## 📦 Vulnerable Dependencies --- -### ✍️ Summary +### ✍️ Summary %s %s --- -### 👇 Details +## 🔬 Research Details --- @@ -263,8 +278,7 @@ func TestSimplifiedOutput_IacContent(t *testing.T) { name: "Single IAC row", iacRows: []formats.SourceCodeRow{ { - Severity: "High", - SeverityNumValue: 3, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 3}, Location: formats.Location{ File: "applicable/req_sw_terraform_azure_redis_auth.tf", StartLine: 11, @@ -273,14 +287,13 @@ func TestSimplifiedOutput_IacContent(t *testing.T) { }, }, }, - expectedOutput: "\n## 🛠️ Infrastructure as Code \n\n\n| SEVERITY | FILE | LINE:COLUMN | FINDING |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| High | applicable/req_sw_terraform_azure_redis_auth.tf | 11:1 | Missing Periodic patching was detected |\n\n", + expectedOutput: "\n## 🛠️ Infrastructure as Code\n\n\n| SEVERITY | FILE | LINE:COLUMN | FINDING |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| High | applicable/req_sw_terraform_azure_redis_auth.tf | 11:1 | Missing Periodic patching was detected |\n\n", }, { name: "Multiple IAC rows", iacRows: []formats.SourceCodeRow{ { - Severity: "High", - SeverityNumValue: 3, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 3}, Location: formats.Location{ File: "applicable/req_sw_terraform_azure_redis_patch.tf", StartLine: 11, @@ -289,8 +302,7 @@ func TestSimplifiedOutput_IacContent(t *testing.T) { }, }, { - Severity: "High", - SeverityNumValue: 3, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 3}, Location: formats.Location{ File: "applicable/req_sw_terraform_azure_redis_auth.tf", StartLine: 11, @@ -299,7 +311,7 @@ func TestSimplifiedOutput_IacContent(t *testing.T) { }, }, }, - expectedOutput: "\n## 🛠️ Infrastructure as Code \n\n\n| SEVERITY | FILE | LINE:COLUMN | FINDING |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| High | applicable/req_sw_terraform_azure_redis_patch.tf | 11:1 | Missing redis firewall definition or start_ip=0.0.0.0 was detected, Missing redis firewall definition or start_ip=0.0.0.0 was detected |\n| High | applicable/req_sw_terraform_azure_redis_auth.tf | 11:1 | Missing Periodic patching was detected |\n\n", + expectedOutput: "\n## 🛠️ Infrastructure as Code\n\n\n| SEVERITY | FILE | LINE:COLUMN | FINDING |\n| :---------------------: | :----------------------------------: | :-----------------------------------: | :---------------------------------: | \n| High | applicable/req_sw_terraform_azure_redis_patch.tf | 11:1 | Missing redis firewall definition or start_ip=0.0.0.0 was detected, Missing redis firewall definition or start_ip=0.0.0.0 was detected |\n| High | applicable/req_sw_terraform_azure_redis_auth.tf | 11:1 | Missing Periodic patching was detected |\n\n", }, } @@ -327,8 +339,7 @@ func TestSimplifiedOutput_GetIacTableContent(t *testing.T) { name: "Single IAC row", iacRows: []formats.SourceCodeRow{ { - Severity: "Medium", - SeverityNumValue: 2, + SeverityDetails: formats.SeverityDetails{Severity: "Medium", SeverityNumValue: 2}, Location: formats.Location{ File: "file1", StartLine: 1, @@ -343,8 +354,7 @@ func TestSimplifiedOutput_GetIacTableContent(t *testing.T) { name: "Multiple IAC rows", iacRows: []formats.SourceCodeRow{ { - Severity: "High", - SeverityNumValue: 3, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 3}, Location: formats.Location{ File: "file1", StartLine: 1, @@ -353,8 +363,7 @@ func TestSimplifiedOutput_GetIacTableContent(t *testing.T) { }, }, { - Severity: "Medium", - SeverityNumValue: 2, + SeverityDetails: formats.SeverityDetails{Severity: "Medium", SeverityNumValue: 2}, Location: formats.Location{ File: "file2", StartLine: 2, @@ -374,3 +383,8 @@ func TestSimplifiedOutput_GetIacTableContent(t *testing.T) { }) } } + +func TestSimplifiedOutput_GetLicensesTableContent(t *testing.T) { + writer := &SimplifiedOutput{} + testGetLicensesTableContent(t, writer) +} diff --git a/utils/outputwriter/standardoutput.go b/utils/outputwriter/standardoutput.go index 9ee439501..ed6b3626d 100644 --- a/utils/outputwriter/standardoutput.go +++ b/utils/outputwriter/standardoutput.go @@ -84,9 +84,9 @@ func (so *StandardOutput) VulnerabilitiesContent(vulnerabilities []formats.Vulne var contentBuilder strings.Builder // Write summary table part contentBuilder.WriteString(fmt.Sprintf(` -## 📦 Vulnerable Dependencies +%s -### ✍️ Summary +%s
@@ -94,10 +94,13 @@ func (so *StandardOutput) VulnerabilitiesContent(vulnerabilities []formats.Vulne
-## 👇 Details +%s `, + vulnerableDependenciesTitle, + summaryTitle, getVulnerabilitiesTableHeader(so.showCaColumn), - getVulnerabilitiesTableContent(vulnerabilities, so))) + getVulnerabilitiesTableContent(vulnerabilities, so), + researchDetailsTitle)) // Write details for each vulnerability for i := range vulnerabilities { if len(vulnerabilities) == 1 { @@ -126,7 +129,7 @@ func (so *StandardOutput) VulnerabilitiesContent(vulnerabilities []formats.Vulne func (so *StandardOutput) ApplicableCveReviewContent(severity, finding, fullDetails, cve, cveDetails, impactedDependency, remediation string) string { var contentBuilder strings.Builder contentBuilder.WriteString(fmt.Sprintf(` -## 📦🔍 Contextual Analysis CVE Vulnerability +%s
@@ -151,6 +154,7 @@ func (so *StandardOutput) ApplicableCveReviewContent(severity, finding, fullDeta `, + contextualAnalysisTitle, GetApplicabilityMarkdownDescription(so.FormattedSeverity(severity, "Applicable"), cve, impactedDependency, finding), fullDetails, cveDetails)) @@ -173,7 +177,7 @@ func (so *StandardOutput) ApplicableCveReviewContent(severity, finding, fullDeta func (so *StandardOutput) IacReviewContent(severity, finding, fullDetails string) string { return fmt.Sprintf(` -## 🛠️ Infrastructure as Code (Iac) Vulnerability +%s
@@ -190,6 +194,7 @@ func (so *StandardOutput) IacReviewContent(severity, finding, fullDetails string `, + iacTitle, GetJasMarkdownDescription(so.FormattedSeverity(severity, "Applicable"), finding), fullDetails) } @@ -302,6 +307,7 @@ func (so *StandardOutput) UntitledForJasMsg() string { if !so.entitledForJas { msg = ` +---
**Frogbot** also supports **Contextual Analysis, Secret Detection and IaC Vulnerabilities Scanning**. This features are included as part of the [JFrog Advanced Security](https://jfrog.com/xray/) package, which isn't enabled on your system. @@ -311,3 +317,22 @@ func (so *StandardOutput) UntitledForJasMsg() string { } return msg } + +func (so *StandardOutput) LicensesContent(licenses []formats.LicenseRow) string { + if len(licenses) == 0 { + return "" + } + return fmt.Sprintf(` +%s + +
+ +%s %s + +
+ +`, + licenseTitle, + licenseTableHeader, + getLicensesTableContent(licenses, so)) +} diff --git a/utils/outputwriter/standardoutput_test.go b/utils/outputwriter/standardoutput_test.go index d0d7440b4..2a4deb250 100644 --- a/utils/outputwriter/standardoutput_test.go +++ b/utils/outputwriter/standardoutput_test.go @@ -19,21 +19,25 @@ func TestStandardOutput_TableRow(t *testing.T) { { name: "Single CVE and no direct dependencies", vulnerability: formats.VulnerabilityOrViolationRow{ - Severity: "Critical", - ImpactedDependencyName: "testdep", - ImpactedDependencyVersion: "1.0.0", - FixedVersions: []string{"2.0.0"}, - Cves: []formats.CveRow{{Id: "CVE-2022-1234"}}, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "Critical"}, + ImpactedDependencyName: "testdep", + ImpactedDependencyVersion: "1.0.0", + }, + FixedVersions: []string{"2.0.0"}, + Cves: []formats.CveRow{{Id: "CVE-2022-1234"}}, }, expected: "| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableCriticalSeverity.png)
Critical | | testdep:1.0.0 | 2.0.0 | CVE-2022-1234 |", }, { name: "Multiple CVEs and no direct dependencies", vulnerability: formats.VulnerabilityOrViolationRow{ - Severity: "High", - ImpactedDependencyName: "testdep2", - ImpactedDependencyVersion: "1.0.0", - FixedVersions: []string{"2.0.0", "3.0.0"}, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "testdep2", + ImpactedDependencyVersion: "1.0.0", + }, + FixedVersions: []string{"2.0.0", "3.0.0"}, Cves: []formats.CveRow{ {Id: "CVE-2022-1234"}, {Id: "CVE-2022-5678"}, @@ -44,33 +48,37 @@ func TestStandardOutput_TableRow(t *testing.T) { { name: "Single CVE and direct dependencies", vulnerability: formats.VulnerabilityOrViolationRow{ - Severity: "Low", - ImpactedDependencyName: "testdep3", - ImpactedDependencyVersion: "1.0.0", - FixedVersions: []string{"2.0.0"}, - Cves: []formats.CveRow{{Id: "CVE-2022-1234"}}, - Components: []formats.ComponentRow{ - {Name: "dep1", Version: "1.0.0"}, - {Name: "dep2", Version: "2.0.0"}, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "Low"}, + ImpactedDependencyName: "testdep3", + ImpactedDependencyVersion: "1.0.0", + Components: []formats.ComponentRow{ + {Name: "dep1", Version: "1.0.0"}, + {Name: "dep2", Version: "2.0.0"}, + }, }, + FixedVersions: []string{"2.0.0"}, + Cves: []formats.CveRow{{Id: "CVE-2022-1234"}}, }, expected: "| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableLowSeverity.png)
Low | dep1:1.0.0
dep2:2.0.0 | testdep3:1.0.0 | 2.0.0 | CVE-2022-1234 |", }, { name: "Multiple CVEs and direct dependencies", vulnerability: formats.VulnerabilityOrViolationRow{ - Severity: "High", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + SeverityDetails: formats.SeverityDetails{Severity: "High"}, + ImpactedDependencyName: "impacted", + ImpactedDependencyVersion: "3.0.0", + Components: []formats.ComponentRow{ + {Name: "dep1", Version: "1.0.0"}, + {Name: "dep2", Version: "2.0.0"}, + }, + }, Cves: []formats.CveRow{ {Id: "CVE-1"}, {Id: "CVE-2"}, }, - Components: []formats.ComponentRow{ - {Name: "dep1", Version: "1.0.0"}, - {Name: "dep2", Version: "2.0.0"}, - }, - ImpactedDependencyName: "impacted", - ImpactedDependencyVersion: "3.0.0", - FixedVersions: []string{"4.0.0", "5.0.0"}, + FixedVersions: []string{"4.0.0", "5.0.0"}, }, expected: "| ![](https://raw.githubusercontent.com/jfrog/frogbot/master/resources/v2/applicableHighSeverity.png)
High | dep1:1.0.0
dep2:2.0.0 | impacted:3.0.0 | 4.0.0
5.0.0 | CVE-1
CVE-2 |", }, @@ -127,18 +135,22 @@ func TestStandardOutput_VulnerabilitiesContent(t *testing.T) { // Create some sample vulnerabilitiesRows for testing vulnerabilitiesRows := []formats.VulnerabilityOrViolationRow{ { - ImpactedDependencyName: "Dependency1", - ImpactedDependencyVersion: "1.0.0", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + ImpactedDependencyName: "Dependency1", + ImpactedDependencyVersion: "1.0.0", + }, }, { - ImpactedDependencyName: "Dependency2", - ImpactedDependencyVersion: "2.0.0", + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + ImpactedDependencyName: "Dependency2", + ImpactedDependencyVersion: "2.0.0", + }, }, } // Set the expected content string based on the sample data expectedContent := fmt.Sprintf(` -## 📦 Vulnerable Dependencies +## 📦 Vulnerable Dependencies ### ✍️ Summary @@ -148,7 +160,7 @@ func TestStandardOutput_VulnerabilitiesContent(t *testing.T) {
-## 👇 Details +## 🔬 Research Details
%s%s %s @@ -194,24 +206,28 @@ func TestStandardOutput_ContentWithContextualAnalysis(t *testing.T) { // Create some sample vulnerabilitiesRows for testing vulnerabilitiesRows = []formats.VulnerabilityOrViolationRow{ { - ImpactedDependencyName: "Dependency1", - ImpactedDependencyVersion: "1.0.0", - Applicable: "Applicable", - Technology: coreutils.Pip, - Cves: []formats.CveRow{{Id: "CVE-2023-1234"}, {Id: "CVE-2023-4321"}}, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + ImpactedDependencyName: "Dependency1", + ImpactedDependencyVersion: "1.0.0", + }, + Applicable: "Applicable", + Technology: coreutils.Pip, + Cves: []formats.CveRow{{Id: "CVE-2023-1234"}, {Id: "CVE-2023-4321"}}, }, { - ImpactedDependencyName: "Dependency2", - ImpactedDependencyVersion: "2.0.0", - Applicable: "Not Applicable", - Technology: coreutils.Pip, - Cves: []formats.CveRow{{Id: "CVE-2022-4321"}}, + ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ + ImpactedDependencyName: "Dependency2", + ImpactedDependencyVersion: "2.0.0", + }, + Applicable: "Not Applicable", + Technology: coreutils.Pip, + Cves: []formats.CveRow{{Id: "CVE-2022-4321"}}, }, } // Set the expected content string based on the sample data expectedContent = fmt.Sprintf(` -## 📦 Vulnerable Dependencies +## 📦 Vulnerable Dependencies ### ✍️ Summary @@ -221,7 +237,7 @@ func TestStandardOutput_ContentWithContextualAnalysis(t *testing.T) {
-## 👇 Details +## 🔬 Research Details
%s%s %s @@ -273,8 +289,7 @@ func TestStandardOutput_IacContent(t *testing.T) { name: "Single IAC row", iacRows: []formats.SourceCodeRow{ { - Severity: "High", - SeverityNumValue: 3, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 3}, Location: formats.Location{ File: "applicable/req_sw_terraform_azure_redis_auth.tf", StartLine: 11, @@ -289,8 +304,7 @@ func TestStandardOutput_IacContent(t *testing.T) { name: "Multiple IAC rows", iacRows: []formats.SourceCodeRow{ { - Severity: "High", - SeverityNumValue: 3, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 3}, Location: formats.Location{ File: "applicable/req_sw_terraform_azure_redis_patch.tf", StartLine: 11, @@ -299,8 +313,7 @@ func TestStandardOutput_IacContent(t *testing.T) { }, }, { - Severity: "High", - SeverityNumValue: 3, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 3}, Location: formats.Location{ File: "applicable/req_sw_terraform_azure_redis_auth.tf", StartLine: 11, @@ -337,8 +350,7 @@ func TestStandardOutput_GetIacTableContent(t *testing.T) { name: "Single IAC row", iacRows: []formats.SourceCodeRow{ { - Severity: "Medium", - SeverityNumValue: 2, + SeverityDetails: formats.SeverityDetails{Severity: "Medium", SeverityNumValue: 2}, Location: formats.Location{ File: "file1", StartLine: 1, @@ -353,8 +365,7 @@ func TestStandardOutput_GetIacTableContent(t *testing.T) { name: "Multiple IAC rows", iacRows: []formats.SourceCodeRow{ { - Severity: "High", - SeverityNumValue: 3, + SeverityDetails: formats.SeverityDetails{Severity: "High", SeverityNumValue: 3}, Location: formats.Location{ File: "file1", StartLine: 1, @@ -363,8 +374,7 @@ func TestStandardOutput_GetIacTableContent(t *testing.T) { }, }, { - Severity: "Medium", - SeverityNumValue: 2, + SeverityDetails: formats.SeverityDetails{Severity: "Medium", SeverityNumValue: 2}, Location: formats.Location{ File: "file2", StartLine: 2, @@ -384,3 +394,8 @@ func TestStandardOutput_GetIacTableContent(t *testing.T) { }) } } + +func TestStandardOutput_GetLicensesTableContent(t *testing.T) { + writer := &StandardOutput{} + testGetLicensesTableContent(t, writer) +} diff --git a/utils/params.go b/utils/params.go index 3d5dfa6c8..98dbe020a 100644 --- a/utils/params.go +++ b/utils/params.go @@ -113,6 +113,7 @@ type Scan struct { FixableOnly bool `yaml:"fixableOnly,omitempty"` FailOnSecurityIssues *bool `yaml:"failOnSecurityIssues,omitempty"` MinSeverity string `yaml:"minSeverity,omitempty"` + AllowedLicenses []string `yaml:"allowedLicenses,omitempty"` Projects []Project `yaml:"projects,omitempty"` EmailDetails `yaml:",inline"` } @@ -182,6 +183,11 @@ func (s *Scan) setDefaultsIfNeeded() (err error) { if len(s.Projects) == 0 { s.Projects = append(s.Projects, Project{}) } + if len(s.AllowedLicenses) == 0 { + if s.AllowedLicenses, err = readArrayParamFromEnv(AllowedLicensesEnv, ","); err != nil && !e.IsMissingEnvErr(err) { + return + } + } for i := range s.Projects { if err = s.Projects[i].setDefaultsIfNeeded(); err != nil { return @@ -198,16 +204,10 @@ type JFrogPlatform struct { func (jp *JFrogPlatform) setDefaultsIfNeeded() (err error) { e := &ErrMissingEnv{} - if jp.Watches == nil { - var watches string - if err = readParamFromEnv(jfrogWatchesEnv, &watches); err != nil && !e.IsMissingEnvErr(err) { + if len(jp.Watches) == 0 { + if jp.Watches, err = readArrayParamFromEnv(jfrogWatchesEnv, WatchesDelimiter); err != nil && !e.IsMissingEnvErr(err) { return } - if watches != "" { - // Remove spaces if exists - watches = strings.ReplaceAll(watches, " ", "") - jp.Watches = strings.Split(watches, WatchesDelimiter) - } } if jp.JFrogProjectKey == "" { @@ -427,11 +427,6 @@ func extractGitParamsFromEnvs() (*Git, error) { if branch != "" { gitEnvParams.Branches = []string{branch} } - // Set the repository name - if err = readParamFromEnv(GitRepoEnv, &gitEnvParams.RepoName); err != nil && !e.IsMissingEnvErr(err) { - return nil, err - } - // Non-mandatory Git Api Endpoint, if not set, default values will be used. if err = readParamFromEnv(GitApiEndpointEnv, &gitEnvParams.APIEndpoint); err != nil && !e.IsMissingEnvErr(err) { return nil, err @@ -439,19 +434,24 @@ func extractGitParamsFromEnvs() (*Git, error) { if err = verifyValidApiEndpoint(gitEnvParams.APIEndpoint); err != nil { return nil, err } - // Set the Git provider + // [Mandatory] Set the Git provider if gitEnvParams.GitProvider, err = extractVcsProviderFromEnv(); err != nil { return nil, err } - // Set the git repository owner name (organization) + // [Mandatory] Set the git repository owner name (organization) if err = readParamFromEnv(GitRepoOwnerEnv, &gitEnvParams.RepoOwner); err != nil { return nil, err } - // Set the access token to the git provider + // [Mandatory] Set the access token to the git provider if err = readParamFromEnv(GitTokenEnv, &gitEnvParams.Token); err != nil { return nil, err } + // [Mandatory] Set the repository name + if err = readParamFromEnv(GitRepoEnv, &gitEnvParams.RepoName); err != nil { + return nil, err + } + // Set Bitbucket Server username // Mandatory only for Bitbucket Server, this authentication detail is required for performing git operations. if err = readParamFromEnv(GitUsernameEnv, &gitEnvParams.Username); err != nil && !e.IsMissingEnvErr(err) { @@ -488,6 +488,21 @@ func verifyValidApiEndpoint(apiEndpoint string) error { return nil } +func readArrayParamFromEnv(envKey, delimiter string) ([]string, error) { + var envValue string + var err error + e := &ErrMissingEnv{} + if err = readParamFromEnv(envKey, &envValue); err != nil && !e.IsMissingEnvErr(err) { + return nil, err + } + if envValue == "" { + return nil, &ErrMissingEnv{VariableName: envKey} + } + // Remove spaces if exists + envValue = strings.ReplaceAll(envValue, " ", "") + return strings.Split(envValue, delimiter), nil +} + func readParamFromEnv(envKey string, paramValue *string) error { *paramValue = getTrimmedEnv(envKey) if *paramValue == "" { @@ -550,7 +565,7 @@ func ReadConfigFromFileSystem(configRelativePath string) (configFileContent []by } log.Debug(FrogbotConfigFile, "found in", fullConfigDirPath) - configFileContent, err = os.ReadFile(fullConfigDirPath) + configFileContent, err = os.ReadFile(filepath.Clean(fullConfigDirPath)) if err != nil { err = fmt.Errorf("an error occurd while reading the %s file at: %s\n%s", FrogbotConfigFile, configRelativePath, err.Error()) } diff --git a/utils/params_test.go b/utils/params_test.go index 74b4df157..8fdf862f8 100644 --- a/utils/params_test.go +++ b/utils/params_test.go @@ -143,6 +143,10 @@ func TestExtractClientInfo(t *testing.T) { SetEnvAndAssert(t, map[string]string{GitRepoOwnerEnv: "jfrog"}) _, err = extractGitParamsFromEnvs() assert.EqualError(t, err, "'JF_GIT_TOKEN' environment variable is missing") + + SetEnvAndAssert(t, map[string]string{GitTokenEnv: "token"}) + _, err = extractGitParamsFromEnvs() + assert.EqualError(t, err, "'JF_GIT_REPO' environment variable is missing") } func TestExtractAndAssertRepoParams(t *testing.T) { @@ -161,6 +165,7 @@ func TestExtractAndAssertRepoParams(t *testing.T) { GitEmailAuthorEnv: "myemail@jfrog.com", MinSeverityEnv: "high", FixableOnlyEnv: "true", + AllowedLicensesEnv: "MIT, Apache-2.0, ISC", }) defer func() { assert.NoError(t, SanitizeEnv()) @@ -191,6 +196,7 @@ func TestExtractAndAssertRepoParams(t *testing.T) { assert.Equal(t, true, repo.AggregateFixes) assert.Equal(t, "myemail@jfrog.com", repo.EmailAuthor) assert.ElementsMatch(t, []string{"watch-2", "watch-1"}, repo.Watches) + assert.ElementsMatch(t, []string{"MIT", "ISC", "Apache-2.0"}, repo.AllowedLicenses) for _, project := range repo.Projects { testExtractAndAssertProjectParams(t, project) } @@ -224,6 +230,7 @@ func TestBuildRepoAggregatorWithEmptyScan(t *testing.T) { assert.False(t, scan.IncludeAllVulnerabilities) assert.False(t, scan.FixableOnly) assert.Empty(t, scan.MinSeverity) + assert.Empty(t, scan.AllowedLicenses) assert.True(t, *scan.FailOnSecurityIssues) assert.Len(t, scan.Projects, 1) project := scan.Projects[0] @@ -337,6 +344,7 @@ func TestGenerateConfigAggregatorFromEnv(t *testing.T) { FailOnSecurityIssuesEnv: "false", MinSeverityEnv: "medium", FixableOnlyEnv: "true", + AllowedLicensesEnv: "MIT, Apache-2.0", GitPullRequestIDEnv: "0", }) defer func() { @@ -367,6 +375,7 @@ func TestGenerateConfigAggregatorFromEnv(t *testing.T) { assert.Equal(t, false, *repo.FailOnSecurityIssues) assert.Equal(t, "Medium", repo.MinSeverity) assert.Equal(t, true, repo.FixableOnly) + assert.ElementsMatch(t, []string{"MIT", "Apache-2.0"}, repo.AllowedLicenses) assert.Equal(t, gitParams.RepoOwner, repo.RepoOwner) assert.Equal(t, gitParams.Token, repo.Token) assert.Equal(t, gitParams.APIEndpoint, repo.APIEndpoint) @@ -521,6 +530,7 @@ func TestBuildMergedRepoAggregator(t *testing.T) { assert.Equal(t, "commit-msg", repo.CommitMessageTemplate) assert.Equal(t, "proj", repo.JFrogProjectKey) assert.Equal(t, "myPullRequests", repo.PullRequestTitleTemplate) + assert.ElementsMatch(t, []string{"ISC", "MIT"}, repo.AllowedLicenses) assert.ElementsMatch(t, []string{"watch-1", "watch-2"}, repo.Watches) project := repo.Projects[0] assert.ElementsMatch(t, []string{"a/b"}, project.WorkingDirs) diff --git a/utils/reviewcomment.go b/utils/reviewcomment.go index 92209765a..76c3df852 100644 --- a/utils/reviewcomment.go +++ b/utils/reviewcomment.go @@ -28,7 +28,7 @@ const ( CommentId = "FrogbotReviewComment" ) -func AddReviewComments(repo *Repository, pullRequestID int, client vcsclient.VcsClient, vulnerabilitiesRows []formats.VulnerabilityOrViolationRow, iacIssues, sastIssues []formats.SourceCodeRow) (err error) { +func AddReviewComments(repo *Repository, pullRequestID int, client vcsclient.VcsClient, issues *IssuesCollection) (err error) { if err = deleteOldReviewComments(repo, pullRequestID, client); err != nil { err = errors.New("couldn't delete pull request review comment: " + err.Error()) return @@ -37,7 +37,7 @@ func AddReviewComments(repo *Repository, pullRequestID int, client vcsclient.Vcs err = errors.New("couldn't delete pull request comment: " + err.Error()) return } - commentsToAdd := getNewReviewComments(repo, vulnerabilitiesRows, iacIssues, sastIssues) + commentsToAdd := getNewReviewComments(repo, issues) if len(commentsToAdd) == 0 { return } @@ -106,10 +106,10 @@ func getRegularCommentContent(comment ReviewComment) string { return content + outputwriter.GetLocationDescription(comment.Location) + comment.CommentInfo.Content } -func getNewReviewComments(repo *Repository, vulnerabilitiesRows []formats.VulnerabilityOrViolationRow, iacIssues, sastIssues []formats.SourceCodeRow) (commentsToAdd []ReviewComment) { +func getNewReviewComments(repo *Repository, issues *IssuesCollection) (commentsToAdd []ReviewComment) { writer := repo.OutputWriter - for _, vulnerability := range vulnerabilitiesRows { + for _, vulnerability := range issues.Vulnerabilities { for _, cve := range vulnerability.Cves { if cve.Applicability != nil { for _, evidence := range cve.Applicability.Evidence { @@ -118,11 +118,11 @@ func getNewReviewComments(repo *Repository, vulnerabilitiesRows []formats.Vulner } } } - for _, iac := range iacIssues { + for _, iac := range issues.Iacs { commentsToAdd = append(commentsToAdd, generateReviewComment(IacComment, iac.Location, generateReviewCommentContent(IacComment, iac, writer))) } - for _, sast := range sastIssues { + for _, sast := range issues.Sast { commentsToAdd = append(commentsToAdd, generateReviewComment(SastComment, sast.Location, generateReviewCommentContent(SastComment, sast, writer))) } return diff --git a/utils/scandetails.go b/utils/scandetails.go index 0026b8e26..3b66d7267 100644 --- a/utils/scandetails.go +++ b/utils/scandetails.go @@ -46,8 +46,8 @@ func (sc *ScanDetails) SetProject(project *Project) *ScanDetails { return sc } -func (sc *ScanDetails) SetXrayGraphScanParams(watches []string, jfrogProjectKey string) *ScanDetails { - sc.XrayGraphScanParams = createXrayScanParams(watches, jfrogProjectKey) +func (sc *ScanDetails) SetXrayGraphScanParams(watches []string, jfrogProjectKey string, includeLicenses bool) *ScanDetails { + sc.XrayGraphScanParams = createXrayScanParams(watches, jfrogProjectKey, includeLicenses) return sc } @@ -96,10 +96,10 @@ func (sc *ScanDetails) SetRepoName(repoName string) *ScanDetails { return sc } -func createXrayScanParams(watches []string, project string) (params *services.XrayGraphScanParams) { +func createXrayScanParams(watches []string, project string, includeLicenses bool) (params *services.XrayGraphScanParams) { params = &services.XrayGraphScanParams{ ScanType: services.Dependency, - IncludeLicenses: false, + IncludeLicenses: includeLicenses, } if len(watches) > 0 { params.Watches = watches @@ -109,7 +109,6 @@ func createXrayScanParams(watches []string, project string) (params *services.Xr params.ProjectKey = project return } - // No context was supplied. We therefore request from Xray to return all known vulnerabilities. params.IncludeVulnerabilities = true return } @@ -153,7 +152,10 @@ func (sc *ScanDetails) runInstallIfNeeded(workDir string) (err error) { log.Info(fmt.Sprintf("Executing '%s %s' at %s", sc.InstallCommandName, strings.Join(sc.InstallCommandArgs, " "), workDir)) output, err := sc.runInstallCommand() if err != nil && !sc.FailOnInstallationErrors() { - log.Info(installationCmdFailedErr, err.Error(), "\n", string(output)) + log.Info(installationCmdFailedErr, err.Error()) + if len(output) > 0 { + log.Info(string(output)) + } // failOnInstallationErrors set to 'false' err = nil } diff --git a/utils/scandetails_test.go b/utils/scandetails_test.go index 8810a3196..6dcaf2826 100644 --- a/utils/scandetails_test.go +++ b/utils/scandetails_test.go @@ -10,25 +10,25 @@ import ( func TestCreateXrayScanParams(t *testing.T) { // Project scanDetails := &ScanDetails{} - scanDetails.SetXrayGraphScanParams(nil, "") + scanDetails.SetXrayGraphScanParams(nil, "", false) assert.Empty(t, scanDetails.Watches) assert.Equal(t, "", scanDetails.ProjectKey) assert.True(t, scanDetails.IncludeVulnerabilities) assert.False(t, scanDetails.IncludeLicenses) // Watches - scanDetails.SetXrayGraphScanParams([]string{"watch-1", "watch-2"}, "") + scanDetails.SetXrayGraphScanParams([]string{"watch-1", "watch-2"}, "", false) assert.Equal(t, []string{"watch-1", "watch-2"}, scanDetails.Watches) assert.Equal(t, "", scanDetails.ProjectKey) assert.False(t, scanDetails.IncludeVulnerabilities) assert.False(t, scanDetails.IncludeLicenses) // Project - scanDetails.SetXrayGraphScanParams(nil, "project") + scanDetails.SetXrayGraphScanParams(nil, "project", true) assert.Empty(t, scanDetails.Watches) assert.Equal(t, "project", scanDetails.ProjectKey) assert.False(t, scanDetails.IncludeVulnerabilities) - assert.False(t, scanDetails.IncludeLicenses) + assert.True(t, scanDetails.IncludeLicenses) } func TestRunInstallIfNeeded(t *testing.T) { diff --git a/utils/testsutils.go b/utils/testsutils.go index 2fe2a8822..6b3740caf 100644 --- a/utils/testsutils.go +++ b/utils/testsutils.go @@ -6,8 +6,10 @@ import ( goGitConfig "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing/object" biutils "github.com/jfrog/build-info-go/utils" + "github.com/jfrog/gofrog/datastructures" "github.com/jfrog/jfrog-cli-core/v2/utils/config" "github.com/jfrog/jfrog-client-go/utils/io/fileutils" + "github.com/owenrumney/go-sarif/v2/sarif" "os" "path/filepath" "strings" @@ -105,3 +107,40 @@ func CreateDotGitWithCommit(t *testing.T, wd, port string, repositoriesPath ...s assert.NoError(t, err) } } + +func GetRunWithDummyResults(results ...*sarif.Result) *sarif.Run { + run := sarif.NewRunWithInformationURI("", "") + ids := datastructures.MakeSet[string]() + for _, result := range results { + if !ids.Exists(*result.RuleID) { + run.Tool.Driver.Rules = append(run.Tool.Driver.Rules, sarif.NewRule(*result.RuleID)) + ids.Add(*result.RuleID) + } + } + return run.WithResults(results) +} + +func GetDummyPassingResult(ruleId string) *sarif.Result { + kind := "pass" + return &sarif.Result{ + Kind: &kind, + RuleID: &ruleId, + } +} + +func GetDummyResultWithOneLocation(fileName string, startLine, startCol int, snippet, ruleId string, level string) *sarif.Result { + return &sarif.Result{ + Locations: []*sarif.Location{ + { + PhysicalLocation: &sarif.PhysicalLocation{ + ArtifactLocation: &sarif.ArtifactLocation{URI: &fileName}, + Region: &sarif.Region{ + StartLine: &startLine, + StartColumn: &startCol, + Snippet: &sarif.ArtifactContent{Text: &snippet}}}, + }, + }, + Level: &level, + RuleID: &ruleId, + } +} diff --git a/utils/utils.go b/utils/utils.go index a2b146213..0ee939155 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -198,7 +198,7 @@ func VulnerabilityDetailsToMD5Hash(vulnerabilities ...formats.VulnerabilityOrVio hash := crypto.MD5.New() var keys []string for _, vuln := range vulnerabilities { - keys = append(keys, GetUniqueID(vuln)) + keys = append(keys, GetVulnerabiltiesUniqueID(vuln)) } sort.Strings(keys) for key, value := range keys { @@ -347,7 +347,7 @@ func BuildServerConfigFile(server *config.ServerDetails) (previousJFrogHomeDir, return } -func GetUniqueID(vulnerability formats.VulnerabilityOrViolationRow) string { +func GetVulnerabiltiesUniqueID(vulnerability formats.VulnerabilityOrViolationRow) string { return xrayutils.GetUniqueKey( vulnerability.ImpactedDependencyName, vulnerability.ImpactedDependencyVersion, @@ -366,3 +366,76 @@ func GetSortedPullRequestComments(client vcsclient.VcsClient, repoOwner, repoNam }) return pullRequestsComments, nil } + +func ConvertSarifPathsToRelative(issues *IssuesCollection, workingDirs ...string) { + convertSarifPathsInCveApplicability(issues.Vulnerabilities, workingDirs...) + convertSarifPathsInIacs(issues.Iacs, workingDirs...) + convertSarifPathsInSecrets(issues.Secrets, workingDirs...) + convertSarifPathsInSast(issues.Sast, workingDirs...) +} + +func convertSarifPathsInCveApplicability(vulnerabilities []formats.VulnerabilityOrViolationRow, workingDirs ...string) { + for _, row := range vulnerabilities { + for _, cve := range row.Cves { + if cve.Applicability != nil { + for i := range cve.Applicability.Evidence { + for _, wd := range workingDirs { + cve.Applicability.Evidence[i].File = xrayutils.ExtractRelativePath(cve.Applicability.Evidence[i].File, wd) + } + } + } + } + } +} + +func convertSarifPathsInIacs(iacs []formats.SourceCodeRow, workingDirs ...string) { + for i := range iacs { + iac := &iacs[i] + for _, wd := range workingDirs { + iac.Location.File = xrayutils.ExtractRelativePath(iac.Location.File, wd) + } + } +} + +func convertSarifPathsInSecrets(secrets []formats.SourceCodeRow, workingDirs ...string) { + for i := range secrets { + secret := &secrets[i] + for _, wd := range workingDirs { + secret.Location.File = xrayutils.ExtractRelativePath(secret.Location.File, wd) + } + } +} + +func convertSarifPathsInSast(sast []formats.SourceCodeRow, workingDirs ...string) { + for i := range sast { + sastIssue := &sast[i] + for _, wd := range workingDirs { + sastIssue.Location.File = xrayutils.ExtractRelativePath(sastIssue.Location.File, wd) + for f := range sastIssue.CodeFlow { + for l := range sastIssue.CodeFlow[f] { + sastIssue.CodeFlow[f][l].File = xrayutils.ExtractRelativePath(sastIssue.CodeFlow[f][l].File, wd) + } + } + } + } +} + +// Normalizes whitespace in text, ensuring that words are separated by a single space, and any extra whitespace is removed. +func normalizeWhitespaces(text string) string { + return strings.Join(strings.Fields(text), " ") +} + +// Converts Technology array into a string with a separator. +func techArrayToString(techsArray []coreutils.Technology, separator string) (result string) { + if len(techsArray) == 0 { + return "" + } + if len(techsArray) < 2 { + return techsArray[0].ToFormal() + } + var techString []string + for _, tech := range techsArray { + techString = append(techString, tech.ToFormal()) + } + return strings.Join(techString, separator) +} diff --git a/utils/utils_test.go b/utils/utils_test.go index a647b06b1..f9c075743 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -113,23 +113,23 @@ func TestFixVersionsMapToMd5Hash(t *testing.T) { }{ { vulnerabilities: []*VulnerabilityDetails{ - {SuggestedFixedVersion: "1.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg", Technology: coreutils.Npm}, IsDirectDependency: false}}, + {SuggestedFixedVersion: "1.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "pkg"}, Technology: coreutils.Npm}, IsDirectDependency: false}}, expectedHash: "5ce60f326e1d1e329b74e3310b34c969", }, { vulnerabilities: []*VulnerabilityDetails{ - {SuggestedFixedVersion: "5.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg", Technology: coreutils.Go}, IsDirectDependency: false}, - {SuggestedFixedVersion: "1.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg2", Technology: coreutils.Go}, IsDirectDependency: false}}, + {SuggestedFixedVersion: "5.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "pkg"}, Technology: coreutils.Go}, IsDirectDependency: false}, + {SuggestedFixedVersion: "1.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "pkg2"}, Technology: coreutils.Go}, IsDirectDependency: false}}, expectedHash: "bf6e3f3204b8df46400785c60e9ff4c9", }, { // The Same map with different order should be the same hash. vulnerabilities: []*VulnerabilityDetails{ - {SuggestedFixedVersion: "1.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg2", Technology: coreutils.Go}, IsDirectDependency: false}, - {SuggestedFixedVersion: "5.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "pkg", Technology: coreutils.Go}, IsDirectDependency: false}}, + {SuggestedFixedVersion: "1.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "pkg2"}, Technology: coreutils.Go}, IsDirectDependency: false}, + {SuggestedFixedVersion: "5.2.3", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "pkg"}, Technology: coreutils.Go}, IsDirectDependency: false}}, expectedHash: "bf6e3f3204b8df46400785c60e9ff4c9", }, { vulnerabilities: []*VulnerabilityDetails{ - {SuggestedFixedVersion: "0.2.33", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyName: "myNuget", Technology: coreutils.Nuget}, IsDirectDependency: false}}, + {SuggestedFixedVersion: "0.2.33", VulnerabilityOrViolationRow: formats.VulnerabilityOrViolationRow{ImpactedDependencyDetails: formats.ImpactedDependencyDetails{ImpactedDependencyName: "myNuget"}, Technology: coreutils.Nuget}, IsDirectDependency: false}}, expectedHash: "ee2d3be06ca4fe53f6ab769e06d74702", }, } @@ -324,3 +324,51 @@ func TestExtractVunerabilitiesDetailsToRows(t *testing.T) { }) } } + +func TestNormalizeWhiteSpace(t *testing.T) { + testCases := []struct { + input string + expected string + }{ + {input: "hello world", expected: "hello world"}, + {input: "hello world", expected: "hello world"}, + {input: " hello world", expected: "hello world"}, + {input: " hello world ", expected: "hello world"}, + {input: " hello world a ", expected: "hello world a"}, + } + for _, tc := range testCases { + t.Run(tc.expected, func(t *testing.T) { + output := normalizeWhitespaces(tc.input) + assert.Equal(t, tc.expected, output) + }) + } +} + +func TestTechArrayToString(t *testing.T) { + testCases := []struct { + techArray []coreutils.Technology + separator string + expected string + }{{ + techArray: []coreutils.Technology{coreutils.Maven, coreutils.Go}, + separator: fixBranchTechSeparator, expected: "Maven-Go", + }, { + techArray: []coreutils.Technology{coreutils.Go}, + separator: fixBranchTechSeparator, expected: "Go", + }, { + techArray: []coreutils.Technology{coreutils.Go}, + separator: pullRequestTitleTechSeparator, expected: "Go", + }, { + techArray: []coreutils.Technology{coreutils.Go, coreutils.Pip, coreutils.Npm}, + separator: pullRequestTitleTechSeparator, expected: "Go,Pip,npm", + }, { + techArray: []coreutils.Technology{coreutils.Go, coreutils.Pip, coreutils.Npm}, + separator: fixBranchTechSeparator, expected: "Go-Pip-npm", + }} + for _, tc := range testCases { + t.Run(tc.expected, func(t *testing.T) { + output := techArrayToString(tc.techArray, tc.separator) + assert.Equal(t, tc.expected, output) + }) + } +}