From 2f486fafca131b94f672f8d8f94d5cea9272e496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl?= Date: Tue, 2 Aug 2022 10:50:32 +0400 Subject: [PATCH 01/55] chore: update driftctl to v0.36.0 --- src/lib/iac/drift/driftctl.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/lib/iac/drift/driftctl.ts b/src/lib/iac/drift/driftctl.ts index a7bfb76185..fdf7df7e85 100644 --- a/src/lib/iac/drift/driftctl.ts +++ b/src/lib/iac/drift/driftctl.ts @@ -35,29 +35,29 @@ export const DCTL_EXIT_CODES = { EXIT_ERROR: 2, }; -export const driftctlVersion = 'v0.35.2'; +export const driftctlVersion = 'v0.36.0'; const driftctlChecksums = { driftctl_darwin_amd64: - '1e21863bb99d104da8a1e33999563cc172ca51bb5b6ac7d3a4bd9678e0285067', + 'c9b44613694931d5033d16cf6396c2611d115f3c6971c8215c04b6ce321e9bb5', 'driftctl_windows_386.exe': - '20dc49a4faebfdbdf9f9198499ba2426ea6cda0666e82d81cd4e08a41516d5e0', + 'e37505fa9875b3d3c29fdfffebbe03f60154aae3e8d7057cad469dfceec47151', driftctl_darwin_arm64: - '37b7a4c72f4db62b056f1b534eb93fbb8dd32c303719ed4af87d9bd4d903fcf6', + 'a18cb7039bf67bf0addf628887cfd12488895492d7e0c3a31a0a51005bc0d583', driftctl_linux_arm64: - '3e6dabf013e097be1aac0e6e0f4ebcc3ada85a1906c6841d57fbe96c9ee9857e', + '6dcc235d511546cc3573f5a7b3fc2a825a4dff7e08df481a55f5826ac6802059', 'driftctl_windows_arm.exe': - '480c330fefdc6e1d58de943817556a1cd183d32d58b6cb20c8127cd3b8753dc4', + 'c7bf2d1f268a5c4b6985d02a0d2e98ecf43ef5bc4de14360568f0233e206e471', driftctl_linux_amd64: - '80b7b99c343e1502f54321987c9f00fa3c381fbea819b1e440a0377b18706fb1', + 'f2b388a6f92772e35320cb2240b68dab2c62c87d4a84ffc88bb42020cb0ab805', 'driftctl_windows_amd64.exe': - 'bbc71047bd75e1bcd80752b7c03c27c0d8d7d93bec72a70eb8bc8220687805de', + '696e067ee37c156b175c51e55481e823fb8601c8d69133cb12ba8a3f2e22aa68', 'driftctl_windows_arm64.exe': - 'be1a5564ec3351503caa16121d192ad8d8e8f287a5324939214b20177c7363e4', + '5531adc30e0d1431b692062bbc7c91536d86f5f5d212a5bd3083fec6007f0be5', driftctl_linux_arm: - 'd04c911bdb86092743077bfbb025bfb8391978236bb381122594aeaa77f9a68f', + 'c6bcd8987f633d310b9872c5635112d8fd479f4117518aa4864fa38874c7869e', driftctl_linux_386: - 'e720c2f3c25594c7b83ffb2123c461283589b6ee73b9a59c1c4f48bb2bac2775', + '864ff0810466ed2917b3347866b5da80fae43e2487b18a563f1d7f299e5f1518', }; const dctlBaseUrl = 'https://static.snyk.io/cli/driftctl/'; From 3f933192d8975af1f6ec4c126c62a554f026f87a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Scha=CC=88fer?= <101886095+PeterSchafer@users.noreply.github.com> Date: Mon, 29 Aug 2022 15:15:44 +0200 Subject: [PATCH 02/55] chore: upgrade pkg from 5.6.0 to 5.8.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: upgrade depcheck from 1.4.1 to 1.4.3 … resolves issue of false positive unused dependencies when running `npx ts-node ./scripts/check-dependencies.ts` Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: pin pkg to the exact version Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: update nodejs 16.14.2 to 16.16.0 Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: disable sudo since the new docker node image … … doesn’t support it Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: inverse default value of ‘npm_global_sudo’ and adapt usage Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: update nodejs versions 14.19.1 to 14.20.0 Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: extend jest matrix test Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> --- .circleci/chocolatey.config | 2 +- .circleci/config.yml | 25 +- .github/workflows/check-dependencies.yml | 2 +- .github/workflows/cli-alert.yml | 2 +- .github/workflows/danger-zone.yml | 2 +- .nvmrc | 2 +- docker-desktop/build.sh | 2 +- package-lock.json | 444 +++++++++++++++-------- package.json | 4 +- 9 files changed, 314 insertions(+), 171 deletions(-) diff --git a/.circleci/chocolatey.config b/.circleci/chocolatey.config index 5ddd113397..2c50e1d6e9 100644 --- a/.circleci/chocolatey.config +++ b/.circleci/chocolatey.config @@ -4,7 +4,7 @@ - + diff --git a/.circleci/config.yml b/.circleci/config.yml index abb2c7a1b0..bb8ea523ff 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -14,7 +14,7 @@ parameters: node_version: type: string # https://circleci.com/developer/images/image/cimg/node - default: '16.14.2' + default: '16.16.0' npm_version: type: string # match whatever's bundled with node_version @@ -74,7 +74,7 @@ commands: default: /mnt/ramdisk/.npm npm_global_sudo: type: boolean - default: true + default: false npm_install: type: boolean default: false @@ -335,7 +335,6 @@ jobs: at: . - install_sdks_windows - setup_npm: - npm_global_sudo: false npm_install: true # reinstalling as workspace node_modules is for linux npm_cache_directory: ~\AppData\Local\npm-cache - run: @@ -358,7 +357,6 @@ jobs: at: . - install_sdks_macos - setup_npm: - npm_global_sudo: false npm_install: true # reinstalling as workspace node_modules is for linux npm_cache_directory: /Users/distiller/.npm - run: @@ -387,6 +385,7 @@ jobs: sudo apt install nodejs npm - setup_npm: npm_cache_directory: /home/circleci/.npm + npm_global_sudo: true - run: name: Configuring artifact command: << parameters.test_snyk_command >> config set "api=${SNYK_API_KEY}" @@ -413,6 +412,7 @@ jobs: sudo apt install nodejs npm - setup_npm: npm_cache_directory: /home/circleci/.npm + npm_global_sudo: true - run: name: Configuring artifact command: << parameters.test_snyk_command >> config set "api=${SNYK_API_KEY}" @@ -425,6 +425,8 @@ jobs: parameters: node_version: type: string + npm_global_sudo: + type: boolean executor: name: docker-node node_version: << parameters.node_version >> @@ -439,6 +441,7 @@ jobs: at: . - install_sdks_linux - setup_npm: + npm_global_sudo: << parameters.npm_global_sudo >> node_version: << parameters.node_version >> - run: name: Configuring Snyk CLI @@ -805,7 +808,15 @@ workflows: - Build matrix: parameters: - node_version: ['12.22.11', '14.19.1', '16.14.2'] + node_version: ['12.22.11', '14.20.0', '16.16.0'] + npm_global_sudo: [true, false] + exclude: + - node_version: '12.22.11' + npm_global_sudo: false + - node_version: '14.20.0' + npm_global_sudo: false + - node_version: '16.16.0' + npm_global_sudo: true - test-tap: name: Tap Tests context: nodejs-install @@ -894,8 +905,8 @@ workflows: - Lint - Tap Tests - Jest Tests (Node v12.22.11) - - Jest Tests (Node v14.19.1) - - Jest Tests (Node v16.14.2) + - Jest Tests (Node v14.20.0) + - Jest Tests (Node v16.16.0) - Acceptance Tests (snyk-win.exe) - Acceptance Tests (snyk-macos) - Acceptance Tests (snyk-linux) diff --git a/.github/workflows/check-dependencies.yml b/.github/workflows/check-dependencies.yml index 6e543c8f1f..45dbf9338e 100644 --- a/.github/workflows/check-dependencies.yml +++ b/.github/workflows/check-dependencies.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '16.14.2' + node-version: '16.16.0' cache: 'npm' - run: npm ci - run: npx ts-node ./scripts/check-dependencies.ts diff --git a/.github/workflows/cli-alert.yml b/.github/workflows/cli-alert.yml index c35b5c9a37..9d017c63b9 100644 --- a/.github/workflows/cli-alert.yml +++ b/.github/workflows/cli-alert.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '16.14.2' + node-version: '16.16.0' cache: 'npm' - run: npm ci - run: npm start diff --git a/.github/workflows/danger-zone.yml b/.github/workflows/danger-zone.yml index fdc9802a6d..13015b3a31 100644 --- a/.github/workflows/danger-zone.yml +++ b/.github/workflows/danger-zone.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '16.14.2' + node-version: '16.16.0' cache: 'npm' - run: npm ci - run: npx danger ci diff --git a/.nvmrc b/.nvmrc index d9f880069d..431076a948 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -16.14.2 +16.16.0 diff --git a/docker-desktop/build.sh b/docker-desktop/build.sh index 66d467b857..f6a20ef435 100755 --- a/docker-desktop/build.sh +++ b/docker-desktop/build.sh @@ -3,7 +3,7 @@ set -euo pipefail platform="${1}" arch="${2}" -node_version="v16.14.2" +node_version="v16.16.0" node_url="https://nodejs.org/dist/${node_version}/node-${node_version}-${platform}-${arch}.tar.gz" build_name="snyk-for-docker-desktop-${platform}-${arch}" build_filename="${build_name}.tar.gz" diff --git a/package-lock.json b/package-lock.json index f454572c05..0ce868fc79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -105,7 +105,7 @@ "copy-webpack-plugin": "^9.0.1", "cross-spawn": "^6.0.5", "danger": "10.7.1", - "depcheck": "^1.4.1", + "depcheck": "^1.4.3", "eslint": "6.8.0", "eslint-config-prettier": "^6.1.0", "eslint-plugin-jest": "^24.4.0", @@ -117,7 +117,7 @@ "nock": "^10.0.6", "node-loader": "^2.0.0", "npm-run-all": "^4.1.5", - "pkg": "5.6.0", + "pkg": "5.8.0", "prettier": "^1.18.2", "proxyquire": "^1.7.4", "sinon": "^4.0.0", @@ -195,14 +195,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", - "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", + "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", "dev": true, "dependencies": { - "@babel/types": "^7.15.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.18.2", + "@jridgewell/gen-mapping": "^0.3.0", + "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" @@ -414,9 +414,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.16.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", - "integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==", + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz", + "integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -633,12 +633,12 @@ } }, "node_modules/@babel/types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", - "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz", + "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1553,6 +1553,54 @@ "node": ">=8" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", + "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -6287,12 +6335,12 @@ "dev": true }, "node_modules/depcheck": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/depcheck/-/depcheck-1.4.2.tgz", - "integrity": "sha512-oYaBLRbF5NMkYxc5rltnqtuPAn25Lx5xPBIJXy5oUVBgrEDDtotCoYUfFH8lvcmSWzgk1Ts9H+f4Rk0oWL51LQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/depcheck/-/depcheck-1.4.3.tgz", + "integrity": "sha512-vy8xe1tlLFu7t4jFyoirMmOR7x7N601ubU9Gkifyr9z8rjBFtEdWHDBMqXyk6OkK+94NXutzddVXJuo0JlUQKQ==", "dev": true, "dependencies": { - "@babel/parser": "^7.12.5", + "@babel/parser": "7.16.4", "@babel/traverse": "^7.12.5", "@vue/compiler-sfc": "^3.0.5", "camelcase": "^6.2.0", @@ -6323,6 +6371,18 @@ "node": ">=10" } }, + "node_modules/depcheck/node_modules/@babel/parser": { + "version": "7.16.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.4.tgz", + "integrity": "sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/depcheck/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -7663,9 +7723,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -7674,7 +7734,7 @@ "micromatch": "^4.0.4" }, "engines": { - "node": ">=8" + "node": ">=8.6.0" } }, "node_modules/fast-glob/node_modules/glob-parent": { @@ -8587,15 +8647,15 @@ } }, "node_modules/globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" }, "engines": { @@ -9046,9 +9106,9 @@ ] }, "node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "engines": { "node": ">= 4" } @@ -9398,9 +9458,9 @@ } }, "node_modules/is-core-module": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", - "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -12988,9 +13048,9 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/minimist-options": { "version": "4.1.0", @@ -14482,26 +14542,25 @@ } }, "node_modules/pkg": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.6.0.tgz", - "integrity": "sha512-mHrAVSQWmHA41RnUmRpC7pK9lNnMfdA16CF3cqOI22a8LZxOQzF7M8YWtA2nfs+d7I0MTDXOtkDsAsFXeCpYjg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.8.0.tgz", + "integrity": "sha512-8h9PUDYFi+LOMLbIyGRdP21g08mAtHidSpofSrf8LWhxUWGHymaRzcopEGiynB5EhQmZUKM6PQ9kCImV2TpdjQ==", "dev": true, "dependencies": { - "@babel/parser": "7.16.2", - "@babel/types": "7.16.0", + "@babel/generator": "7.18.2", + "@babel/parser": "7.18.4", + "@babel/types": "7.18.4", "chalk": "^4.1.2", - "escodegen": "^2.0.0", "fs-extra": "^9.1.0", - "globby": "^11.0.4", + "globby": "^11.1.0", "into-stream": "^6.0.0", - "minimist": "^1.2.5", + "is-core-module": "2.9.0", + "minimist": "^1.2.6", "multistream": "^4.1.0", - "pkg-fetch": "3.3.0", + "pkg-fetch": "3.4.2", "prebuild-install": "6.1.4", - "progress": "^2.0.3", - "resolve": "^1.20.0", - "stream-meter": "^1.0.4", - "tslib": "2.3.1" + "resolve": "^1.22.0", + "stream-meter": "^1.0.4" }, "bin": { "pkg": "lib-es5/bin.js" @@ -14528,9 +14587,9 @@ } }, "node_modules/pkg-fetch": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.3.0.tgz", - "integrity": "sha512-xJnIZ1KP+8rNN+VLafwu4tEeV4m8IkFBDdCFqmAJz9K1aiXEtbARmdbEe6HlXWGSVuShSHjFXpfkKRkDBQ5kiA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.4.2.tgz", + "integrity": "sha512-0+uijmzYcnhC0hStDjm/cl2VYdrmVVBpe7Q8k9YBojxmR5tG8mvR9/nooQq3QSXiQqORDVOTY3XqMEqJVIzkHA==", "dev": true, "dependencies": { "chalk": "^4.1.2", @@ -14617,9 +14676,9 @@ } }, "node_modules/pkg-fetch/node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, "dependencies": { "agent-base": "6", @@ -14630,12 +14689,15 @@ } }, "node_modules/pkg-fetch/node_modules/lru-cache": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz", - "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==", + "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": ">=12" + "node": ">=10" } }, "node_modules/pkg-fetch/node_modules/node-fetch": { @@ -14659,18 +14721,18 @@ } }, "node_modules/pkg-fetch/node_modules/semver": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.6.tgz", - "integrity": "sha512-HZWqcgwLsjaX1HBD31msI/rXktuIhS+lWvdE4kN9z+8IVT4Itc7vqU2WvYsyD6/sjYCt4dEKH/m1M3dwI9CC5w==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "dependencies": { - "lru-cache": "^7.4.0" + "lru-cache": "^6.0.0" }, "bin": { "semver": "bin/semver.js" }, "engines": { - "node": "^10.0.0 || ^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=10" } }, "node_modules/pkg-fetch/node_modules/supports-color": { @@ -14688,25 +14750,31 @@ "node_modules/pkg-fetch/node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, "node_modules/pkg-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=", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true }, "node_modules/pkg-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=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, + "node_modules/pkg-fetch/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/pkg/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -14777,12 +14845,6 @@ "node": ">=8" } }, - "node_modules/pkg/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, "node_modules/please-upgrade-node": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", @@ -15712,13 +15774,17 @@ "dev": true }, "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -17792,6 +17858,18 @@ "node": ">=0.10.0" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -20038,14 +20116,14 @@ } }, "@babel/generator": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", - "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", + "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", "dev": true, "requires": { - "@babel/types": "^7.15.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.18.2", + "@jridgewell/gen-mapping": "^0.3.0", + "jsesc": "^2.5.1" } }, "@babel/helper-compilation-targets": { @@ -20203,9 +20281,9 @@ } }, "@babel/parser": { - "version": "7.16.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.2.tgz", - "integrity": "sha512-RUVpT0G2h6rOZwqLDTrKk7ksNv7YpAilTnYe1/Q+eDjxEceRMKVWbCsX7t8h6C1qCFi/1Y8WZjcEPBAFG27GPw==", + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.4.tgz", + "integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -20364,12 +20442,12 @@ } }, "@babel/types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.0.tgz", - "integrity": "sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==", + "version": "7.18.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz", + "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.15.7", + "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" } }, @@ -21040,6 +21118,45 @@ } } }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", + "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -25011,12 +25128,12 @@ "dev": true }, "depcheck": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/depcheck/-/depcheck-1.4.2.tgz", - "integrity": "sha512-oYaBLRbF5NMkYxc5rltnqtuPAn25Lx5xPBIJXy5oUVBgrEDDtotCoYUfFH8lvcmSWzgk1Ts9H+f4Rk0oWL51LQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/depcheck/-/depcheck-1.4.3.tgz", + "integrity": "sha512-vy8xe1tlLFu7t4jFyoirMmOR7x7N601ubU9Gkifyr9z8rjBFtEdWHDBMqXyk6OkK+94NXutzddVXJuo0JlUQKQ==", "dev": true, "requires": { - "@babel/parser": "^7.12.5", + "@babel/parser": "7.16.4", "@babel/traverse": "^7.12.5", "@vue/compiler-sfc": "^3.0.5", "camelcase": "^6.2.0", @@ -25041,6 +25158,12 @@ "yargs": "^16.1.0" }, "dependencies": { + "@babel/parser": { + "version": "7.16.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.4.tgz", + "integrity": "sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng==", + "dev": true + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -26062,9 +26185,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -26802,15 +26925,15 @@ } }, "globby": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", - "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "requires": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", "slash": "^3.0.0" } }, @@ -27154,9 +27277,9 @@ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" }, "immediate": { "version": "3.0.6", @@ -27406,9 +27529,9 @@ "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" }, "is-core-module": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", - "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "dev": true, "requires": { "has": "^1.0.3" @@ -30142,9 +30265,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "minimist-options": { "version": "4.1.0", @@ -31304,26 +31427,25 @@ "dev": true }, "pkg": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.6.0.tgz", - "integrity": "sha512-mHrAVSQWmHA41RnUmRpC7pK9lNnMfdA16CF3cqOI22a8LZxOQzF7M8YWtA2nfs+d7I0MTDXOtkDsAsFXeCpYjg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.8.0.tgz", + "integrity": "sha512-8h9PUDYFi+LOMLbIyGRdP21g08mAtHidSpofSrf8LWhxUWGHymaRzcopEGiynB5EhQmZUKM6PQ9kCImV2TpdjQ==", "dev": true, "requires": { - "@babel/parser": "7.16.2", - "@babel/types": "7.16.0", + "@babel/generator": "7.18.2", + "@babel/parser": "7.18.4", + "@babel/types": "7.18.4", "chalk": "^4.1.2", - "escodegen": "^2.0.0", "fs-extra": "^9.1.0", - "globby": "^11.0.4", + "globby": "^11.1.0", "into-stream": "^6.0.0", - "minimist": "^1.2.5", + "is-core-module": "2.9.0", + "minimist": "^1.2.6", "multistream": "^4.1.0", - "pkg-fetch": "3.3.0", + "pkg-fetch": "3.4.2", "prebuild-install": "6.1.4", - "progress": "^2.0.3", - "resolve": "^1.20.0", - "stream-meter": "^1.0.4", - "tslib": "2.3.1" + "resolve": "^1.22.0", + "stream-meter": "^1.0.4" }, "dependencies": { "ansi-styles": { @@ -31374,12 +31496,6 @@ "requires": { "has-flag": "^4.0.0" } - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true } } }, @@ -31393,9 +31509,9 @@ } }, "pkg-fetch": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.3.0.tgz", - "integrity": "sha512-xJnIZ1KP+8rNN+VLafwu4tEeV4m8IkFBDdCFqmAJz9K1aiXEtbARmdbEe6HlXWGSVuShSHjFXpfkKRkDBQ5kiA==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.4.2.tgz", + "integrity": "sha512-0+uijmzYcnhC0hStDjm/cl2VYdrmVVBpe7Q8k9YBojxmR5tG8mvR9/nooQq3QSXiQqORDVOTY3XqMEqJVIzkHA==", "dev": true, "requires": { "chalk": "^4.1.2", @@ -31458,9 +31574,9 @@ "dev": true }, "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, "requires": { "agent-base": "6", @@ -31468,10 +31584,13 @@ } }, "lru-cache": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.7.3.tgz", - "integrity": "sha512-WY9wjJNQt9+PZilnLbuFKM+SwDull9+6IAguOrarOMoOHTcJ9GnXSO11+Gw6c7xtDkBkthR57OZMtZKYr+1CEw==", - "dev": true + "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" + } }, "node-fetch": { "version": "2.6.7", @@ -31483,12 +31602,12 @@ } }, "semver": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.6.tgz", - "integrity": "sha512-HZWqcgwLsjaX1HBD31msI/rXktuIhS+lWvdE4kN9z+8IVT4Itc7vqU2WvYsyD6/sjYCt4dEKH/m1M3dwI9CC5w==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { - "lru-cache": "^7.4.0" + "lru-cache": "^6.0.0" } }, "supports-color": { @@ -31503,24 +31622,30 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", "dev": true }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.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 } } }, @@ -32227,13 +32352,14 @@ "dev": true }, "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-alpn": { @@ -33906,6 +34032,12 @@ } } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", diff --git a/package.json b/package.json index bf20cab7db..d435c50b01 100644 --- a/package.json +++ b/package.json @@ -149,7 +149,7 @@ "copy-webpack-plugin": "^9.0.1", "cross-spawn": "^6.0.5", "danger": "10.7.1", - "depcheck": "^1.4.1", + "depcheck": "^1.4.3", "eslint": "6.8.0", "eslint-config-prettier": "^6.1.0", "eslint-plugin-jest": "^24.4.0", @@ -161,7 +161,7 @@ "nock": "^10.0.6", "node-loader": "^2.0.0", "npm-run-all": "^4.1.5", - "pkg": "5.6.0", + "pkg": "5.8.0", "prettier": "^1.18.2", "proxyquire": "^1.7.4", "sinon": "^4.0.0", From d7ad7f48ce3a64a8a17e08b9af547d57ec473a69 Mon Sep 17 00:00:00 2001 From: Ofek Atar Date: Wed, 31 Aug 2022 15:34:46 +0300 Subject: [PATCH 03/55] chore: Updated snyk-iac-test version to v0.26.0 --- .../v2/local-cache/policy-engine/constants/utils.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts index 0dc2cd847b..3a151fd781 100644 --- a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts +++ b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts @@ -1,11 +1,11 @@ import * as os from 'os'; -const policyEngineChecksums = `2b96e44012ab42e6a181a954c83af374e1bbdcb0f39782504421730615dd8b0d snyk-iac-test_0.25.0_Windows_arm64.exe -6ed11a2f3fed1a382a69e5ad47eed37951490688dc0d0ea31c15b81e6022a98c snyk-iac-test_0.25.0_Linux_arm64 -94cf0ffdb75108f826f2df2495f579c48e016f1fc5b63f25205f79a72523930d snyk-iac-test_0.25.0_Windows_x86_64.exe -af7c9d6334cb6bc2af981a950035eeca755c26a366a7142e5b3774341104a80c snyk-iac-test_0.25.0_Darwin_x86_64 -e6f8838f419d8639b2358d84b134d0abd2cc6c855730db5ab27464f32911d8c2 snyk-iac-test_0.25.0_Darwin_arm64 -e89838a2d41ebc90e4575558c09074044b3e2966494590fa13b31efe9ed3efc6 snyk-iac-test_0.25.0_Linux_x86_64 +const policyEngineChecksums = `104f3a8d8d1835f9621007fb7976a837ee8946510f41f7fc50323f728cebb21c snyk-iac-test_0.26.0_Darwin_arm64 +61bfc743d4392952eb7de3f3c4cdb6e0dfb4a491d0ca24d67c929fc3656d6c5f snyk-iac-test_0.26.0_Linux_x86_64 +73847b5bcc0f42cc8acd918f0dff97ee917a64ce84991785a8e6c46a6c4bc6f2 snyk-iac-test_0.26.0_Linux_arm64 +ac9100c8a1314a22fe7db7df8faa7d6be0aa6ba986f2db172f727fe004a0853d snyk-iac-test_0.26.0_Windows_x86_64.exe +ad2983ff583989608e259441de12b6871d9e9dcb994eb81214e9dbb14d3b3dd4 snyk-iac-test_0.26.0_Darwin_x86_64 +c7de20ee54fd66c885e2bbe37b8c1d533464a525a5abdbc1d86a6a5c8a76b2b8 snyk-iac-test_0.26.0_Windows_arm64.exe `; export const policyEngineVersion = getPolicyEngineVersion(); From 8cf181582031466702aecd4cc0e39f64408dcef3 Mon Sep 17 00:00:00 2001 From: Ofek Atar Date: Wed, 31 Aug 2022 15:35:06 +0300 Subject: [PATCH 04/55] feat: Added support for depth-detection --- src/cli/commands/test/iac/v2/assert-iac-options.ts | 1 + src/cli/commands/test/iac/v2/index.ts | 3 +++ src/lib/iac/test/v2/scan/index.ts | 4 ++++ src/lib/iac/test/v2/types.ts | 1 + 4 files changed, 9 insertions(+) diff --git a/src/cli/commands/test/iac/v2/assert-iac-options.ts b/src/cli/commands/test/iac/v2/assert-iac-options.ts index c2601411ee..048a5f4310 100644 --- a/src/cli/commands/test/iac/v2/assert-iac-options.ts +++ b/src/cli/commands/test/iac/v2/assert-iac-options.ts @@ -22,6 +22,7 @@ const keys: (keyof IaCTestFlags)[] = [ 'scan', 'experimental', 'var-file', + 'detectionDepth', // PolicyOptions 'ignore-policy', 'policy-path', diff --git a/src/cli/commands/test/iac/v2/index.ts b/src/cli/commands/test/iac/v2/index.ts index d452ba90d6..9577387a1f 100644 --- a/src/cli/commands/test/iac/v2/index.ts +++ b/src/cli/commands/test/iac/v2/index.ts @@ -54,6 +54,8 @@ async function prepareTestConfig( const projectTags = parseTags(options); const targetName = getFlag(options, 'target-name'); const remoteRepoUrl = getFlag(options, 'remote-repo-url'); + const depthDetection = + parseInt(getFlag(options, 'depth-detection') as string) || undefined; const attributes = parseAttributes(options); const policy = await findAndLoadPolicy(process.cwd(), 'iac', options); const scan = options.scan ?? 'resource-changes'; @@ -73,6 +75,7 @@ async function prepareTestConfig( remoteRepoUrl, policy: policy?.toString(), scan, + depthDetection, }; } diff --git a/src/lib/iac/test/v2/scan/index.ts b/src/lib/iac/test/v2/scan/index.ts index e471b137b1..72a4eeec1b 100644 --- a/src/lib/iac/test/v2/scan/index.ts +++ b/src/lib/iac/test/v2/scan/index.ts @@ -113,6 +113,10 @@ function processFlags( flags.push('-project-lifecycle', options.attributes.lifecycle.join(',')); } + if (options.depthDetection) { + flags.push('-depth-detection', `${options.depthDetection}`); + } + if (options.projectTags) { const stringifiedTags = options.projectTags .map((tag) => { diff --git a/src/lib/iac/test/v2/types.ts b/src/lib/iac/test/v2/types.ts index deb8224939..08ae6cf0f0 100644 --- a/src/lib/iac/test/v2/types.ts +++ b/src/lib/iac/test/v2/types.ts @@ -17,4 +17,5 @@ export interface TestConfig { remoteRepoUrl?: string; policy?: string; scan: string; + depthDetection?: number; } From 20dcdae8d097cc798a46df39b903cf00f9111e8c Mon Sep 17 00:00:00 2001 From: magdziarek Date: Wed, 31 Aug 2022 18:14:01 +0200 Subject: [PATCH 05/55] fix: matching configurations error on gradle version catalog --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index f454572c05..2da4bc286b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,7 +68,7 @@ "snyk-cpp-plugin": "2.20.0", "snyk-docker-plugin": "^5.1.2", "snyk-go-plugin": "^1.19.0", - "snyk-gradle-plugin": "3.21.1", + "snyk-gradle-plugin": "^3.22.1", "snyk-module": "3.1.0", "snyk-mvn-plugin": "2.31.0", "snyk-nodejs-lockfile-parser": "1.38.0", @@ -16702,9 +16702,9 @@ } }, "node_modules/snyk-gradle-plugin": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.21.1.tgz", - "integrity": "sha512-ZL2GXi76owUi5Y4SvasBtpxvMi/6thxBNDXjghbzBmnMAZUanc2vwZldE7aRa7vvyVv60Jao9ommH2IMye7s7Q==", + "version": "3.22.1", + "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.22.1.tgz", + "integrity": "sha512-MXLo1aGoE95d2rKNajwFZ4GcpYj/ap0WkyQXnVMfFM0NeYHOeZU/cQqIbY49/14vtu/Gtqlc5phHjDhERYx3Rg==", "dependencies": { "@snyk/cli-interface": "2.11.3", "@snyk/dep-graph": "^1.28.0", @@ -32990,9 +32990,9 @@ } }, "snyk-gradle-plugin": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.21.1.tgz", - "integrity": "sha512-ZL2GXi76owUi5Y4SvasBtpxvMi/6thxBNDXjghbzBmnMAZUanc2vwZldE7aRa7vvyVv60Jao9ommH2IMye7s7Q==", + "version": "3.22.1", + "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.22.1.tgz", + "integrity": "sha512-MXLo1aGoE95d2rKNajwFZ4GcpYj/ap0WkyQXnVMfFM0NeYHOeZU/cQqIbY49/14vtu/Gtqlc5phHjDhERYx3Rg==", "requires": { "@snyk/cli-interface": "2.11.3", "@snyk/dep-graph": "^1.28.0", diff --git a/package.json b/package.json index bf20cab7db..a794763ccb 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "snyk-cpp-plugin": "2.20.0", "snyk-docker-plugin": "^5.1.2", "snyk-go-plugin": "^1.19.0", - "snyk-gradle-plugin": "3.21.1", + "snyk-gradle-plugin": "^3.22.1", "snyk-module": "3.1.0", "snyk-mvn-plugin": "2.31.0", "snyk-nodejs-lockfile-parser": "1.38.0", From 424289d01ffcb702780633f63812d52570c0eb60 Mon Sep 17 00:00:00 2001 From: Amir Moualem Date: Thu, 1 Sep 2022 13:48:16 +0300 Subject: [PATCH 06/55] chore: remove code ownership from Capsule Team Capsule has been split and no longer exists. --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d249c6b5ad..a5268d56c1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -81,9 +81,9 @@ test/tap/cli-fail-on-pinnable.test.ts @snyk/snyk-open-source test/tap/cli-monitor.acceptance.test.ts @snyk/snyk-open-source test/tap/cli-test.acceptance.test.ts @snyk/snyk-open-source test/tap/cli.test.ts @snyk/hammer -test/tap/container.test.ts @snyk/capsule @snyk/potion +test/tap/container.test.ts @snyk/potion test/tap/display-test-results.test.ts @snyk/snyk-open-source -test/tap/docker-token.test.ts @snyk/capsule @snyk/potion +test/tap/docker-token.test.ts @snyk/potion test/tap/endpoint-config.test.ts @snyk/hammer test/tap/find-files.test.ts @snyk/snyk-open-source test/tap/monitor-target.test.ts @snyk/snyk-open-source From 581ebb88075678fa74474c5a4e4f413785172727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Scha=CC=88fer?= <101886095+PeterSchafer@users.noreply.github.com> Date: Wed, 24 Aug 2022 10:48:24 +0200 Subject: [PATCH 07/55] chore: handle GOOS alpine in Makefile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: add alpine build to workflow Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: run v2 jtest on alpine Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: add test alpine to workflow Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: disable usage of sudo Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: temporarily add libc dependency to enable running Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: add additional dependencies for running tests on alpine Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: remove docker and docker-compose from alpine tests without docker installed proxy tests will be skipped unfortunately running docker on alpine was causing more issues so this the attempt to skip these tests Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: use musl explictly to compile for alpine Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: remove glibc installation again Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: install maven for alpine tests Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: temporarily skip failing test Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: adapt step name Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> --- .circleci/config.yml | 52 ++++++++++++++++++++ cliv2/Makefile | 12 +++-- test/jest/acceptance/iac/file-output.spec.ts | 52 +++++++++++--------- 3 files changed, 90 insertions(+), 26 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index abb2c7a1b0..d0c51c0148 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -37,6 +37,9 @@ parameters: default: '7.0.4' executors: + alpine: + docker: + - image: alpine:3.16.2 docker-node: parameters: node_version: @@ -369,6 +372,31 @@ jobs: command: npm run test:acceptance -- --selectProjects snyk environment: TEST_SNYK_COMMAND: << parameters.test_snyk_command >> + test-alpine: + parameters: + test_snyk_command: + type: string + executor: alpine + working_directory: /home/circleci/snyk + steps: + - checkout + - attach_workspace: + at: . + - run: + name: Installing Node.js + other test dependencies + command: | + apk add --update nodejs npm bash maven + - setup_npm: + npm_cache_directory: /home/circleci/.npm + npm_global_sudo: false + - run: + name: Configuring artifact + command: << parameters.test_snyk_command >> config set "api=${SNYK_API_KEY}" + - run: + name: Testing artifact + command: npm run test:acceptance -- --selectProjects snyk + environment: + TEST_SNYK_COMMAND: << parameters.test_snyk_command >> test-linux: parameters: test_snyk_command: @@ -605,6 +633,9 @@ jobs: type: string go_arch: type: string + c_compiler: + type: string + default: '' executor: linux working_directory: /home/circleci/snyk steps: @@ -615,10 +646,12 @@ jobs: version: << pipeline.parameters.go_version >> - restore_cache: key: go-build-{{ arch }}-{{ checksum "cliv2/go.sum" }} + - run: sudo apt-get install musl-tools - run: name: Build << parameters.go_os >>/<< parameters.go_arch >> working_directory: ./cliv2 environment: + CC: << parameters.c_compiler >> GOOS: << parameters.go_os >> GOARCH: << parameters.go_arch >> CLI_V1_LOCATION: ../binary-releases @@ -975,6 +1008,18 @@ workflows: only: - /^.*cliv2.*$/ - master + - v2-build-artifact: + name: v2 / Build (alpine/amd64) + requires: + - Build (snyk-alpine) + go_os: alpine + go_arch: amd64 + c_compiler: /usr/bin/musl-gcc + filters: + branches: + only: + - /^.*cliv2.*$/ + - master - v2-test-linux-amd64: name: v2 / Integration Tests (linux/amd64) requires: @@ -1000,6 +1045,12 @@ workflows: requires: - v2 / Build (windows/amd64) # Tests for backwards compatibility with CLIv1 + - test-alpine: + name: v2 / Jest Acceptance Tests (alpine/amd64) + context: nodejs-install + requires: + - v2 / Build (alpine/amd64) + test_snyk_command: /home/circleci/snyk/cliv2/bin/snyk_alpine_amd64 - test-linux: name: v2 / Jest Acceptance Tests (linux/amd64) context: nodejs-install @@ -1043,6 +1094,7 @@ workflows: - v2-prepare-release: name: v2 / Prepare Release requires: + - v2 / Build (alpine/amd64) - v2 / Build (linux/amd64) - v2 / Build (linux/arm64) - v2 / Sign (darwin/amd64) diff --git a/cliv2/Makefile b/cliv2/Makefile index b67d72d9d2..50d5f06815 100644 --- a/cliv2/Makefile +++ b/cliv2/Makefile @@ -24,6 +24,7 @@ SRCS = $(shell find $(WORKING_DIR) -type f -name '*.go') -include $(CACHE_DIR)/version.mk # the platform string used by the deployed binaries is not excatly OS-ARCH so we need to translate a bit +_GO_OS = $(GOOS) _V1_OS = $(GOOS) _V1_ARCH = $(GOARCH) _EMPTY = @@ -58,6 +59,9 @@ ifneq ($(CLI_V1_LOCATION), $(_EMPTY)) _V1_DOWNLOAD = false endif +ifeq ($(_GO_OS), alpine) + _GO_OS = linux +endif # some globally assembled variables APPLICATION_NAME = snyk @@ -73,8 +77,8 @@ V1_EMBEDDED_FILE_OUTPUT = embedded$(_SEPARATOR)$(V2_PLATFORM_STRING).go HASH_STRING = $(HASH)$(HASH_ALGORITHM) TEST_SNYK_EXECUTABLE_PATH=$(BUILD_DIR)/$(V2_EXECUTABLE_NAME) TEST_EXECUTABLE_NAME = $(TEST_NAME)$(_SEPARATOR)$(V2_PLATFORM_STRING)$(_EXE_POSTFIX) -SIGN_SCRIPT = sign_$(GOOS).sh -ISSIGNED_SCRIPT = issigned_$(GOOS).sh +SIGN_SCRIPT = sign_$(_GO_OS).sh +ISSIGNED_SCRIPT = issigned_$(_GO_OS).sh # some make file variables LOG_PREFIX = -- @@ -140,7 +144,7 @@ configure: $(V2_DIRECTORY)/cliv2.version $(CACHE_DIR) $(CACHE_DIR)/version.mk $( $(BUILD_DIR)/$(V2_EXECUTABLE_NAME): $(BUILD_DIR) $(SRCS) @echo "$(LOG_PREFIX) Building ( $(BUILD_DIR)/$(V2_EXECUTABLE_NAME) )" - @GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOCMD) build -o $(BUILD_DIR)/$(V2_EXECUTABLE_NAME) $(WORKING_DIR)/cmd/cliv2/main.go + @GOOS=$(_GO_OS) GOARCH=$(GOARCH) $(GOCMD) build -o $(BUILD_DIR)/$(V2_EXECUTABLE_NAME) $(WORKING_DIR)/cmd/cliv2/main.go $(BUILD_DIR)/$(V2_EXECUTABLE_NAME).$(HASH_STRING): @echo "$(LOG_PREFIX) Generating checksum ( $(BUILD_DIR)/$(V2_EXECUTABLE_NAME).$(HASH_STRING) )" @@ -148,7 +152,7 @@ $(BUILD_DIR)/$(V2_EXECUTABLE_NAME).$(HASH_STRING): $(BUILD_DIR)/$(TEST_EXECUTABLE_NAME): @echo "$(LOG_PREFIX) Building test executable ( $(BUILD_DIR)/$(TEST_EXECUTABLE_NAME) )" - @GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOCMD) test -c -o $(BUILD_DIR)/$(TEST_EXECUTABLE_NAME) main_integration_test.go + @GOOS=$(_GO_OS) GOARCH=$(GOARCH) $(GOCMD) test -c -o $(BUILD_DIR)/$(TEST_EXECUTABLE_NAME) main_integration_test.go .PHONY: build build: configure $(BUILD_DIR)/$(V2_EXECUTABLE_NAME) $(BUILD_DIR)/$(V2_EXECUTABLE_NAME).$(HASH_STRING) diff --git a/test/jest/acceptance/iac/file-output.spec.ts b/test/jest/acceptance/iac/file-output.spec.ts index c7a565bb5c..080dea7d65 100644 --- a/test/jest/acceptance/iac/file-output.spec.ts +++ b/test/jest/acceptance/iac/file-output.spec.ts @@ -85,28 +85,36 @@ describe('iac test --sarif-file-output', () => { expect(startLine).not.toEqual(-1); }); - it('returns the correct paths for provided path', async () => { - const sarifOutputFilename = path.join(__dirname, `${uuidv4()}.sarif`); - const { stdout } = await run( - `snyk iac test ./iac/file-output/sg_open_ssh.tf --sarif-file-output=${sarifOutputFilename}`, - ); - expect(stdout).toMatch('Organization:'); - - const outputFileContents = readFileSync(sarifOutputFilename, 'utf-8'); - unlinkSync(sarifOutputFilename); - const jsonObj = JSON.parse(outputFileContents); - const actualPhysicalLocation = - jsonObj?.runs?.[0].results[0].locations[0].physicalLocation - .artifactLocation.uri; - const actualProjectRoot = - jsonObj?.runs?.[0].originalUriBaseIds.PROJECTROOT.uri; - expect(actualPhysicalLocation).toEqual( - 'test/fixtures/iac/file-output/sg_open_ssh.tf', - ); - expect(actualProjectRoot).toEqual( - pathToFileURL(path.join(path.resolve(''), '/')).href, - ); - }); + if ( + process.env.TEST_SNYK_COMMAND && + process.env.TEST_SNYK_COMMAND.includes('alpine') + ) { + // This test is temporarily skipped on Alpine Linux. + it.skip('returns the correct paths for provided path', async () => {}); + } else { + it('returns the correct paths for provided path', async () => { + const sarifOutputFilename = path.join(__dirname, `${uuidv4()}.sarif`); + const { stdout } = await run( + `snyk iac test ./iac/file-output/sg_open_ssh.tf --sarif-file-output=${sarifOutputFilename}`, + ); + expect(stdout).toMatch('Organization:'); + + const outputFileContents = readFileSync(sarifOutputFilename, 'utf-8'); + unlinkSync(sarifOutputFilename); + const jsonObj = JSON.parse(outputFileContents); + const actualPhysicalLocation = + jsonObj?.runs?.[0].results[0].locations[0].physicalLocation + .artifactLocation.uri; + const actualProjectRoot = + jsonObj?.runs?.[0].originalUriBaseIds.PROJECTROOT.uri; + expect(actualPhysicalLocation).toEqual( + 'test/fixtures/iac/file-output/sg_open_ssh.tf', + ); + expect(actualProjectRoot).toEqual( + pathToFileURL(path.join(path.resolve(''), '/')).href, + ); + }); + } it('does not include file content in analytics logs', async () => { const { stdout, exitCode } = await run( From 537372d26b05ca5c0f6a73fa6a6be3438e6c78fc Mon Sep 17 00:00:00 2001 From: Yair Zohar Date: Wed, 31 Aug 2022 15:31:49 +0300 Subject: [PATCH 08/55] feat: add --var-file support --- .../assert-iac-options-flag.ts | 12 ++++--- .../test/iac/v2/assert-iac-options.ts | 35 +++++++++++++++++++ src/cli/commands/test/iac/v2/index.ts | 2 ++ .../policy-engine/constants/utils.ts | 12 +++---- src/lib/iac/test/v2/scan/index.ts | 4 +++ src/lib/iac/test/v2/types.ts | 1 + 6 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/cli/commands/test/iac/local-execution/assert-iac-options-flag.ts b/src/cli/commands/test/iac/local-execution/assert-iac-options-flag.ts index bbd45bb276..17fcc631c0 100644 --- a/src/cli/commands/test/iac/local-execution/assert-iac-options-flag.ts +++ b/src/cli/commands/test/iac/local-execution/assert-iac-options-flag.ts @@ -78,11 +78,9 @@ export class FeatureFlagError extends CustomError { } export class FlagValueError extends CustomError { - constructor(key: string, value: string) { + constructor(key: string, value: string, supportedValues: string) { const flag = getFlagName(key); - const msg = `Unsupported value "${value}" provided to flag "${flag}".\nSupported values are: ${SUPPORTED_TF_PLAN_SCAN_MODES.join( - ', ', - )}`; + const msg = `Unsupported value "${value}" provided to flag "${flag}".\nSupported values are: ${supportedValues}`; super(msg); this.code = IaCErrorCodes.FlagValueError; this.strCode = getErrorStringCode(this.code); @@ -152,7 +150,11 @@ export function assertTerraformPlanModes(scanModeArgValue: string) { scanModeArgValue as TerraformPlanScanMode, ) ) { - throw new FlagValueError('scan', scanModeArgValue); + throw new FlagValueError( + 'scan', + scanModeArgValue, + SUPPORTED_TF_PLAN_SCAN_MODES.join(', '), + ); } } diff --git a/src/cli/commands/test/iac/v2/assert-iac-options.ts b/src/cli/commands/test/iac/v2/assert-iac-options.ts index 048a5f4310..506c296e56 100644 --- a/src/cli/commands/test/iac/v2/assert-iac-options.ts +++ b/src/cli/commands/test/iac/v2/assert-iac-options.ts @@ -1,6 +1,12 @@ +import { existsSync } from 'fs'; +import { extname } from 'path'; +import { SEVERITIES, SEVERITY } from '../../../../../lib/snyk-test/common'; + +import { InvalidVarFilePath } from '../local-execution'; import { assertTerraformPlanModes, FlagError, + FlagValueError, } from '../local-execution/assert-iac-options-flag'; import { IaCTestFlags } from '../local-execution/types'; @@ -40,7 +46,36 @@ export function assertIacV2Options(options: IaCTestFlags): void { } } + if (options.severityThreshold) { + assertSeverityOptions(options.severityThreshold); + } + + if (options['var-file']) { + assertVarFileOptions(options['var-file']); + } + if (options.scan) { assertTerraformPlanModes(options.scan as string); } } + +function assertSeverityOptions(severity: SEVERITY) { + const validSeverityOptions = SEVERITIES.map((s) => s.verboseName); + + if (!validSeverityOptions.includes(severity)) { + throw new FlagValueError( + 'severityThreshold', + severity, + validSeverityOptions.join(', '), + ); + } +} + +function assertVarFileOptions(filePath: string) { + if (!existsSync(filePath)) { + throw new InvalidVarFilePath(filePath); + } + if (extname(filePath) !== '.tfvars') { + throw new FlagValueError('var-file', filePath, '.tfvars file'); + } +} diff --git a/src/cli/commands/test/iac/v2/index.ts b/src/cli/commands/test/iac/v2/index.ts index 9577387a1f..14373b8838 100644 --- a/src/cli/commands/test/iac/v2/index.ts +++ b/src/cli/commands/test/iac/v2/index.ts @@ -59,6 +59,7 @@ async function prepareTestConfig( const attributes = parseAttributes(options); const policy = await findAndLoadPolicy(process.cwd(), 'iac', options); const scan = options.scan ?? 'resource-changes'; + const varFile = options['var-file']; return { paths, @@ -75,6 +76,7 @@ async function prepareTestConfig( remoteRepoUrl, policy: policy?.toString(), scan, + varFile, depthDetection, }; } diff --git a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts index 3a151fd781..518d34f493 100644 --- a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts +++ b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts @@ -1,11 +1,11 @@ import * as os from 'os'; -const policyEngineChecksums = `104f3a8d8d1835f9621007fb7976a837ee8946510f41f7fc50323f728cebb21c snyk-iac-test_0.26.0_Darwin_arm64 -61bfc743d4392952eb7de3f3c4cdb6e0dfb4a491d0ca24d67c929fc3656d6c5f snyk-iac-test_0.26.0_Linux_x86_64 -73847b5bcc0f42cc8acd918f0dff97ee917a64ce84991785a8e6c46a6c4bc6f2 snyk-iac-test_0.26.0_Linux_arm64 -ac9100c8a1314a22fe7db7df8faa7d6be0aa6ba986f2db172f727fe004a0853d snyk-iac-test_0.26.0_Windows_x86_64.exe -ad2983ff583989608e259441de12b6871d9e9dcb994eb81214e9dbb14d3b3dd4 snyk-iac-test_0.26.0_Darwin_x86_64 -c7de20ee54fd66c885e2bbe37b8c1d533464a525a5abdbc1d86a6a5c8a76b2b8 snyk-iac-test_0.26.0_Windows_arm64.exe +const policyEngineChecksums = `283cb07a894f8252733e6634bef84fbc4fe98eac338239493753e20477150abb snyk-iac-test_0.27.0_Darwin_arm64 +55c6cae0b4805047d0f0d8f3eea74f12a4233211499cc2f006cee633f1f2e7b8 snyk-iac-test_0.27.0_Windows_x86_64.exe +7a845e2108c309a7bde435342b69d3ed172a36971779dbc2e1a9a96582f1c4fb snyk-iac-test_0.27.0_Windows_arm64.exe +a06de762874686612d9d42b2eb165979f334413f6460a675f0559e8e56a264dc snyk-iac-test_0.27.0_Linux_x86_64 +ac3ece2e1d59927330c996d968dc5bf84faaa766f85402b56b3ae15fe2fae313 snyk-iac-test_0.27.0_Linux_arm64 +d96eda3334548db4dc17ea9892b94f48a3a4187af13090118e04cdbd23c821b7 snyk-iac-test_0.27.0_Darwin_x86_64 `; export const policyEngineVersion = getPolicyEngineVersion(); diff --git a/src/lib/iac/test/v2/scan/index.ts b/src/lib/iac/test/v2/scan/index.ts index 72a4eeec1b..42ffefac07 100644 --- a/src/lib/iac/test/v2/scan/index.ts +++ b/src/lib/iac/test/v2/scan/index.ts @@ -146,6 +146,10 @@ function processFlags( flags.push('-remote-repo-url', options.remoteRepoUrl); } + if (options.varFile) { + flags.push('-var-file', options.varFile); + } + return flags; } diff --git a/src/lib/iac/test/v2/types.ts b/src/lib/iac/test/v2/types.ts index 08ae6cf0f0..b44652801b 100644 --- a/src/lib/iac/test/v2/types.ts +++ b/src/lib/iac/test/v2/types.ts @@ -17,5 +17,6 @@ export interface TestConfig { remoteRepoUrl?: string; policy?: string; scan: string; + varFile?: string; depthDetection?: number; } From 8893f81c39ee66dc61454a6f9e0036dccd8d3b81 Mon Sep 17 00:00:00 2001 From: Lucian Rosu Date: Thu, 1 Sep 2022 15:40:14 +0300 Subject: [PATCH 09/55] fix: bump golang plugin version --- package-lock.json | 32 +++++++++++++++++++++++++------- package.json | 2 +- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index e8c036ddfe..3da684c7f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,7 +67,7 @@ "snyk-config": "4.0.0", "snyk-cpp-plugin": "2.20.0", "snyk-docker-plugin": "^5.1.2", - "snyk-go-plugin": "^1.19.0", + "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "^3.22.1", "snyk-module": "3.1.0", "snyk-mvn-plugin": "2.31.0", @@ -12608,6 +12608,17 @@ "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", "dev": true }, + "node_modules/lookpath": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/lookpath/-/lookpath-1.2.2.tgz", + "integrity": "sha512-k2Gmn8iV6qdME3ztZC2spubmQISimFOPLuQKiPaLcVdRz0IpdxrNClVepMlyTJlhodm/zG/VfbkWERm3kUIh+Q==", + "bin": { + "lookpath": "bin/lookpath.js" + }, + "engines": { + "npm": ">=6.13.4" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -16730,13 +16741,14 @@ } }, "node_modules/snyk-go-plugin": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/snyk-go-plugin/-/snyk-go-plugin-1.19.0.tgz", - "integrity": "sha512-KC8kBXBx3Qd2ro9ZQv+AGqMrElRLogmmLac/uuSt5rfV3o2wVHnuxPN+YUfr0PgH5lOdMeIeqaYCpWEsc4GhJQ==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/snyk-go-plugin/-/snyk-go-plugin-1.19.2.tgz", + "integrity": "sha512-Lu4HOqbQFQn8eRWbZLqJeHrSxl+y6sOxU5GpHbQN5N3jxB4el49DngLktdef4P285rBvsv2MSwAZnRDEMPeTmw==", "dependencies": { "@snyk/dep-graph": "^1.23.1", "@snyk/graphlib": "2.1.9-patch.3", "debug": "^4.1.1", + "lookpath": "^1.2.2", "snyk-go-parser": "1.4.1", "tmp": "0.2.1", "tslib": "^1.10.0" @@ -29935,6 +29947,11 @@ "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", "dev": true }, + "lookpath": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/lookpath/-/lookpath-1.2.2.tgz", + "integrity": "sha512-k2Gmn8iV6qdME3ztZC2spubmQISimFOPLuQKiPaLcVdRz0IpdxrNClVepMlyTJlhodm/zG/VfbkWERm3kUIh+Q==" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -33085,13 +33102,14 @@ } }, "snyk-go-plugin": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/snyk-go-plugin/-/snyk-go-plugin-1.19.0.tgz", - "integrity": "sha512-KC8kBXBx3Qd2ro9ZQv+AGqMrElRLogmmLac/uuSt5rfV3o2wVHnuxPN+YUfr0PgH5lOdMeIeqaYCpWEsc4GhJQ==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/snyk-go-plugin/-/snyk-go-plugin-1.19.2.tgz", + "integrity": "sha512-Lu4HOqbQFQn8eRWbZLqJeHrSxl+y6sOxU5GpHbQN5N3jxB4el49DngLktdef4P285rBvsv2MSwAZnRDEMPeTmw==", "requires": { "@snyk/dep-graph": "^1.23.1", "@snyk/graphlib": "2.1.9-patch.3", "debug": "^4.1.1", + "lookpath": "^1.2.2", "snyk-go-parser": "1.4.1", "tmp": "0.2.1", "tslib": "^1.10.0" diff --git a/package.json b/package.json index add9f8b758..9d658c2f42 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "snyk-config": "4.0.0", "snyk-cpp-plugin": "2.20.0", "snyk-docker-plugin": "^5.1.2", - "snyk-go-plugin": "^1.19.0", + "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "^3.22.1", "snyk-module": "3.1.0", "snyk-mvn-plugin": "2.31.0", From 5940f43841395b25a1c14f216eb3e0ee2f53416c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Scha=CC=88fer?= <101886095+PeterSchafer@users.noreply.github.com> Date: Thu, 1 Sep 2022 15:05:33 +0200 Subject: [PATCH 10/55] chore: remove skipping test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: add a comment to understand why this test should not be run Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> --- test/jest/acceptance/iac/update-exclude-policy.spec.ts | 8 -------- test/jest/acceptance/proxy-behavior.spec.ts | 3 ++- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/test/jest/acceptance/iac/update-exclude-policy.spec.ts b/test/jest/acceptance/iac/update-exclude-policy.spec.ts index b998c44a0b..0e1e76f906 100644 --- a/test/jest/acceptance/iac/update-exclude-policy.spec.ts +++ b/test/jest/acceptance/iac/update-exclude-policy.spec.ts @@ -4,18 +4,10 @@ import * as fs from 'fs'; import * as rimraf from 'rimraf'; import * as path from 'path'; import { findAndLoadPolicy } from '../../../../src/lib/policy'; -import { isCLIV2 } from '../../util/isCLIV2'; jest.setTimeout(50000); describe('iac update-exclude-policy', () => { - if (isCLIV2()) { - // eslint-disable-next-line jest/no-focused-tests - it.only('CLIv2 not yet supported', () => { - console.warn('Skipping test as CLIv2 does not support it yet.'); - }); - } - let run: typeof Run; let teardown: () => void; diff --git a/test/jest/acceptance/proxy-behavior.spec.ts b/test/jest/acceptance/proxy-behavior.spec.ts index 1960fd686b..fe94b87412 100644 --- a/test/jest/acceptance/proxy-behavior.spec.ts +++ b/test/jest/acceptance/proxy-behavior.spec.ts @@ -94,7 +94,8 @@ describe('Proxy configuration behavior', () => { }); if (!isCLIV2()) { - it('does not try to connect to the HTTPS_PROXY when it is set', async () => { + // This scenario should actually work, an http request should directly go through and not hit the proxy if protocol upgrade is disabled. + it('needle behavior - only HTTPS Proxy is set but HTTP request (without protocol upgrade) fails.', async () => { const { code, stderr } = await runSnykCLI(`woof -d`, { env: { ...process.env, From db21498a9f628c0907abd4bbb41e0e988409f349 Mon Sep 17 00:00:00 2001 From: magdziarek Date: Fri, 2 Sep 2022 12:25:00 +0200 Subject: [PATCH 11/55] fix: filter subprojects on unique path --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3da684c7f3..ba1050aabd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,7 +68,7 @@ "snyk-cpp-plugin": "2.20.0", "snyk-docker-plugin": "^5.1.2", "snyk-go-plugin": "1.19.2", - "snyk-gradle-plugin": "^3.22.1", + "snyk-gradle-plugin": "3.22.2", "snyk-module": "3.1.0", "snyk-mvn-plugin": "2.31.0", "snyk-nodejs-lockfile-parser": "1.38.0", @@ -16780,9 +16780,9 @@ } }, "node_modules/snyk-gradle-plugin": { - "version": "3.22.1", - "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.22.1.tgz", - "integrity": "sha512-MXLo1aGoE95d2rKNajwFZ4GcpYj/ap0WkyQXnVMfFM0NeYHOeZU/cQqIbY49/14vtu/Gtqlc5phHjDhERYx3Rg==", + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.22.2.tgz", + "integrity": "sha512-5zBsEEq9SrQI59OFAnalZJ5hWCKM/LF/JUa3x8F1HVayqNzjMSIqiNa4d4oleMzHo9Rp6QUih1I1J8nbtpwnHg==", "dependencies": { "@snyk/cli-interface": "2.11.3", "@snyk/dep-graph": "^1.28.0", @@ -33134,9 +33134,9 @@ } }, "snyk-gradle-plugin": { - "version": "3.22.1", - "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.22.1.tgz", - "integrity": "sha512-MXLo1aGoE95d2rKNajwFZ4GcpYj/ap0WkyQXnVMfFM0NeYHOeZU/cQqIbY49/14vtu/Gtqlc5phHjDhERYx3Rg==", + "version": "3.22.2", + "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.22.2.tgz", + "integrity": "sha512-5zBsEEq9SrQI59OFAnalZJ5hWCKM/LF/JUa3x8F1HVayqNzjMSIqiNa4d4oleMzHo9Rp6QUih1I1J8nbtpwnHg==", "requires": { "@snyk/cli-interface": "2.11.3", "@snyk/dep-graph": "^1.28.0", diff --git a/package.json b/package.json index 9d658c2f42..0df8aa29a3 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "snyk-cpp-plugin": "2.20.0", "snyk-docker-plugin": "^5.1.2", "snyk-go-plugin": "1.19.2", - "snyk-gradle-plugin": "^3.22.1", + "snyk-gradle-plugin": "3.22.2", "snyk-module": "3.1.0", "snyk-mvn-plugin": "2.31.0", "snyk-nodejs-lockfile-parser": "1.38.0", From 12d8e57d367fbac93b45662b6a158e26f3657bd0 Mon Sep 17 00:00:00 2001 From: Ilianna Papastefanou Date: Tue, 30 Aug 2022 16:37:25 +0100 Subject: [PATCH 12/55] feat: create temp filepath for iac engine to write results This commit creates a temporary filepath and passes it through the -output flag to the snyk-iac-test executable. The snyk-iac-test will then write all the results to this file, which the CLI will have to read and present to the user. --- .../policy-engine/constants/utils.ts | 12 +++--- src/lib/iac/test/v2/scan/index.ts | 42 ++++++++++++------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts index 518d34f493..62b496e7a8 100644 --- a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts +++ b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts @@ -1,11 +1,11 @@ import * as os from 'os'; -const policyEngineChecksums = `283cb07a894f8252733e6634bef84fbc4fe98eac338239493753e20477150abb snyk-iac-test_0.27.0_Darwin_arm64 -55c6cae0b4805047d0f0d8f3eea74f12a4233211499cc2f006cee633f1f2e7b8 snyk-iac-test_0.27.0_Windows_x86_64.exe -7a845e2108c309a7bde435342b69d3ed172a36971779dbc2e1a9a96582f1c4fb snyk-iac-test_0.27.0_Windows_arm64.exe -a06de762874686612d9d42b2eb165979f334413f6460a675f0559e8e56a264dc snyk-iac-test_0.27.0_Linux_x86_64 -ac3ece2e1d59927330c996d968dc5bf84faaa766f85402b56b3ae15fe2fae313 snyk-iac-test_0.27.0_Linux_arm64 -d96eda3334548db4dc17ea9892b94f48a3a4187af13090118e04cdbd23c821b7 snyk-iac-test_0.27.0_Darwin_x86_64 +const policyEngineChecksums = `0cbcdc8f4a7652835355f010d5cb97597055577e624799428c62819d74773b7e snyk-iac-test_0.28.0_Windows_arm64.exe +28637249844c060dc950c6d3fdb31e1ff2d96bfe76291fb383d5c94ee2db7b26 snyk-iac-test_0.28.0_Linux_x86_64 +45629e08ff8c3bfc601773d38705c19ea3abc2b8c33ee7174c97eb5669aa73f9 snyk-iac-test_0.28.0_Linux_arm64 +5a5066edc9dc8daf61fe57f57e844cff59c91c0fdb70f3efda3fe8260f06e801 snyk-iac-test_0.28.0_Windows_x86_64.exe +db669ad313d222184e07c02f3540b06c62de283ef2e57a75ee1df4116f1831a3 snyk-iac-test_0.28.0_Darwin_x86_64 +eb0b99c469eb31f930852466bb1e8b9e576a0bf22ea17dc951762f824009c18a snyk-iac-test_0.28.0_Darwin_arm64 `; export const policyEngineVersion = getPolicyEngineVersion(); diff --git a/src/lib/iac/test/v2/scan/index.ts b/src/lib/iac/test/v2/scan/index.ts index 42ffefac07..088e84e5a6 100644 --- a/src/lib/iac/test/v2/scan/index.ts +++ b/src/lib/iac/test/v2/scan/index.ts @@ -4,11 +4,7 @@ import { CustomError } from '../../../../errors'; import { IaCErrorCodes } from '../../../../../cli/commands/test/iac/local-execution/types'; import { getErrorStringCode } from '../../../../../cli/commands/test/iac/local-execution/error-utils'; import * as newDebug from 'debug'; -import { - mapSnykIacTestOutputToTestOutput, - SnykIacTestOutput, - TestOutput, -} from './results'; +import { mapSnykIacTestOutputToTestOutput, TestOutput } from './results'; import * as os from 'os'; import * as fs from 'fs'; import * as path from 'path'; @@ -27,16 +23,21 @@ export function scan( policyEnginePath: string, rulesBundlePath: string, ): TestOutput { - const configPath = createConfig(options); + const { + tempConfig: configPath, + tempOutput: outputPath, + tempDir: tempDirPath, + } = createTemporaryFiles(options); try { return scanWithConfig( options, policyEnginePath, rulesBundlePath, configPath, + outputPath, ); } finally { - deleteConfig(configPath); + deleteTemporaryFiles(tempDirPath); } } @@ -45,8 +46,9 @@ function scanWithConfig( policyEnginePath: string, rulesBundlePath: string, configPath: string, + outputPath: string, ): TestOutput { - const args = processFlags(options, rulesBundlePath, configPath); + const args = processFlags(options, rulesBundlePath, configPath, outputPath); args.push(...options.paths); @@ -66,21 +68,23 @@ function scanWithConfig( throw new ScanError(`spawning process: ${process.error}`); } - let snykIacTestOutput: SnykIacTestOutput; + let snykIacTestOutput: string, parsedSnykIacTestOutput; try { - snykIacTestOutput = JSON.parse(process.stdout); + snykIacTestOutput = fs.readFileSync(outputPath, 'utf-8'); + parsedSnykIacTestOutput = JSON.parse(snykIacTestOutput); } catch (e) { throw new ScanError(`invalid output encoding: ${e}`); } - return mapSnykIacTestOutputToTestOutput(snykIacTestOutput); + return mapSnykIacTestOutputToTestOutput(parsedSnykIacTestOutput); } function processFlags( options: TestConfig, rulesBundlePath: string, configPath: string, + outputPath: string, ) { const flags = [ '-cache-dir', @@ -91,6 +95,8 @@ function processFlags( configPath, ]; + flags.push('-output', outputPath); + if (options.severityThreshold) { flags.push('-severity-threshold', options.severityThreshold); } @@ -153,10 +159,13 @@ function processFlags( return flags; } -function createConfig(options: TestConfig): string { +function createTemporaryFiles( + options: TestConfig, +): { tempConfig: string; tempOutput: string; tempDir: string } { try { const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'snyk-')); const tempConfig = path.join(tempDir, 'config.json'); + const tempOutput = path.join(tempDir, 'output.json'); const configData = JSON.stringify({ org: options.orgSettings.meta.org, @@ -168,16 +177,17 @@ function createConfig(options: TestConfig): string { }); fs.writeFileSync(tempConfig, configData); + fs.writeFileSync(tempOutput, ''); - return tempConfig; + return { tempConfig, tempOutput, tempDir }; } catch (e) { - throw new ScanError(`unable to create config file: ${e}`); + throw new ScanError(`unable to create config/output file: ${e}`); } } -function deleteConfig(configPath) { +function deleteTemporaryFiles(tempDirPath: string) { try { - rimraf.sync(path.dirname(configPath)); + rimraf.sync(tempDirPath); } catch (e) { debug('unable to delete temporary directory', e); } From 3609d7db74381b63c17d1f62f5d3fbc9ca385f96 Mon Sep 17 00:00:00 2001 From: Yaron Schwimmer Date: Tue, 30 Aug 2022 09:52:23 +0300 Subject: [PATCH 13/55] feat: container python app scan --- package-lock.json | 36 +++++++++++++++++++----------------- package.json | 2 +- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index ba1050aabd..de3d667d55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,7 +66,7 @@ "semver": "^6.0.0", "snyk-config": "4.0.0", "snyk-cpp-plugin": "2.20.0", - "snyk-docker-plugin": "^5.1.2", + "snyk-docker-plugin": "^5.3.2", "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.22.2", "snyk-module": "3.1.0", @@ -2357,11 +2357,11 @@ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" }, "node_modules/@snyk/snyk-docker-pull": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@snyk/snyk-docker-pull/-/snyk-docker-pull-3.7.3.tgz", - "integrity": "sha512-tbxk8fd5c83WPsxm2vX1P0BItfw1M+aNxrlNNwRhRi31OTO0WwR55PbcurMWtFT+LdW7ASRbAi/CC0+aePpj2A==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@snyk/snyk-docker-pull/-/snyk-docker-pull-3.7.4.tgz", + "integrity": "sha512-8SFtc3dDYjcj8rI1IzCyS7DKHKuXSwtEQ/bFrZsOCDZxvFLIaJAxnXPiyx2j11AYU20zChb1302vsySwXxDh+g==", "dependencies": { - "@snyk/docker-registry-v2-client": "^2.7.1", + "@snyk/docker-registry-v2-client": "^2.7.2", "child-process": "^1.0.2", "tar-stream": "^2.2.0", "tmp": "^0.2.1" @@ -16512,14 +16512,14 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/snyk-docker-plugin": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.1.2.tgz", - "integrity": "sha512-PqWl3jcQyBMJ6Fm7h1NJghMLW5V2GDzNjM6LKTN6mCsmXW2M7Xmr1kUakPaWmIOEsrVClFROCWzevww6Tq+GoQ==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.3.2.tgz", + "integrity": "sha512-QIbQD9sA6hkadiZaO/8nhyXFTWew5P25MbTb53pCjB7b58X+u8skaoYKIFzWpqjSumf0/cq0R01E0Sxvykvc3Q==", "dependencies": { "@snyk/composer-lockfile-parser": "^1.4.1", "@snyk/dep-graph": "^2.3.0", "@snyk/rpm-parser": "^2.3.2", - "@snyk/snyk-docker-pull": "^3.7.3", + "@snyk/snyk-docker-pull": "^3.7.4", "adm-zip": "^0.5.5", "chalk": "^2.4.2", "debug": "^4.1.1", @@ -16531,6 +16531,7 @@ "mkdirp": "^1.0.4", "semver": "^7.3.4", "snyk-nodejs-lockfile-parser": "1.40.0", + "snyk-poetry-lockfile-parser": "^1.1.7", "tar-stream": "^2.1.0", "tmp": "^0.2.1", "tslib": "^1", @@ -21934,11 +21935,11 @@ } }, "@snyk/snyk-docker-pull": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@snyk/snyk-docker-pull/-/snyk-docker-pull-3.7.3.tgz", - "integrity": "sha512-tbxk8fd5c83WPsxm2vX1P0BItfw1M+aNxrlNNwRhRi31OTO0WwR55PbcurMWtFT+LdW7ASRbAi/CC0+aePpj2A==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@snyk/snyk-docker-pull/-/snyk-docker-pull-3.7.4.tgz", + "integrity": "sha512-8SFtc3dDYjcj8rI1IzCyS7DKHKuXSwtEQ/bFrZsOCDZxvFLIaJAxnXPiyx2j11AYU20zChb1302vsySwXxDh+g==", "requires": { - "@snyk/docker-registry-v2-client": "^2.7.1", + "@snyk/docker-registry-v2-client": "^2.7.2", "child-process": "^1.0.2", "tar-stream": "^2.2.0", "tmp": "^0.2.1" @@ -32918,14 +32919,14 @@ } }, "snyk-docker-plugin": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.1.2.tgz", - "integrity": "sha512-PqWl3jcQyBMJ6Fm7h1NJghMLW5V2GDzNjM6LKTN6mCsmXW2M7Xmr1kUakPaWmIOEsrVClFROCWzevww6Tq+GoQ==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.3.2.tgz", + "integrity": "sha512-QIbQD9sA6hkadiZaO/8nhyXFTWew5P25MbTb53pCjB7b58X+u8skaoYKIFzWpqjSumf0/cq0R01E0Sxvykvc3Q==", "requires": { "@snyk/composer-lockfile-parser": "^1.4.1", "@snyk/dep-graph": "^2.3.0", "@snyk/rpm-parser": "^2.3.2", - "@snyk/snyk-docker-pull": "^3.7.3", + "@snyk/snyk-docker-pull": "^3.7.4", "adm-zip": "^0.5.5", "chalk": "^2.4.2", "debug": "^4.1.1", @@ -32937,6 +32938,7 @@ "mkdirp": "^1.0.4", "semver": "^7.3.4", "snyk-nodejs-lockfile-parser": "1.40.0", + "snyk-poetry-lockfile-parser": "^1.1.7", "tar-stream": "^2.1.0", "tmp": "^0.2.1", "tslib": "^1", diff --git a/package.json b/package.json index 0df8aa29a3..a932c4b6fe 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "semver": "^6.0.0", "snyk-config": "4.0.0", "snyk-cpp-plugin": "2.20.0", - "snyk-docker-plugin": "^5.1.2", + "snyk-docker-plugin": "^5.3.2", "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.22.2", "snyk-module": "3.1.0", From 3fa6b91a4a7224d7c8c8a296873d32b46d13a163 Mon Sep 17 00:00:00 2001 From: Ofek Atar Date: Thu, 1 Sep 2022 14:31:07 +0300 Subject: [PATCH 14/55] chore: Add issue remediation to test output --- .../formatters/iac-output/text/formatters.ts | 16 +++++++- src/lib/iac/test/v2/json.ts | 39 ++++++++++++------- src/lib/iac/test/v2/sarif.ts | 15 +++++-- src/lib/iac/test/v2/scan/results.ts | 4 +- .../fixtures/experimental-json-output.json | 24 ++++++------ .../fixtures/experimental-sarif-output.json | 8 ++-- .../fixtures/snyk-iac-test-results.json | 8 ++-- .../snyk-iac-test-text-output-data.json | 28 +++++++++---- 8 files changed, 94 insertions(+), 48 deletions(-) diff --git a/src/lib/formatters/iac-output/text/formatters.ts b/src/lib/formatters/iac-output/text/formatters.ts index f88f062ade..f0aa8e9516 100644 --- a/src/lib/formatters/iac-output/text/formatters.ts +++ b/src/lib/formatters/iac-output/text/formatters.ts @@ -1,4 +1,5 @@ import { FormattedResult } from '../../../../cli/commands/test/iac/local-execution/types'; +import { iacRemediationTypes } from '../../../iac/constants'; import { Results, Vulnerability } from '../../../iac/test/v2/scan/results'; import { SEVERITY } from '../../../snyk-test/legacy'; import { IacOutputMeta } from '../../../types'; @@ -167,7 +168,7 @@ function formatSnykIacTestScanResultNewOutput( resultsBySeverity[vulnerability.severity]!.push({ issue: formatSnykIacTestScanVulnerability(vulnerability), targetFile: vulnerability.resource.file, - projectType: vulnerability.resource.type, + projectType: vulnerability.resource.kind, }); }); } @@ -178,6 +179,8 @@ function formatSnykIacTestScanResultNewOutput( function formatSnykIacTestScanVulnerability( vulnerability: Vulnerability, ): Issue { + const resolve = extractResolve(vulnerability); + return { id: vulnerability.rule.id, severity: vulnerability.severity, @@ -186,10 +189,19 @@ function formatSnykIacTestScanVulnerability( cloudConfigPath: formatCloudConfigPath(vulnerability), issue: vulnerability.rule.title, impact: vulnerability.rule.description, - resolve: '', + resolve, documentation: vulnerability.rule.documentation, + remediation: { + [iacRemediationTypes[vulnerability.resource.kind]]: resolve, + }, }; } +function extractResolve(vulnerability: Vulnerability): string { + const newLineIdx = vulnerability.remediation.search(/\r?\n|\r/g); + return newLineIdx < 0 + ? vulnerability.remediation + : vulnerability.remediation.substring(0, newLineIdx); +} function formatCloudConfigPath(vulnerability: Vulnerability): string[] { const cloudConfigPath = vulnerability.resource.id.split('.'); diff --git a/src/lib/iac/test/v2/json.ts b/src/lib/iac/test/v2/json.ts index e4faba11aa..0274cfd164 100644 --- a/src/lib/iac/test/v2/json.ts +++ b/src/lib/iac/test/v2/json.ts @@ -6,7 +6,7 @@ import { IacOrgSettings } from '../../../../cli/commands/test/iac/local-executio import { Resource, ScanError, TestOutput, Vulnerability } from './scan/results'; import * as path from 'path'; import { createErrorMappedResultsForJsonOutput } from '../../../formatters/test/format-test-results'; -import { IacProjectType } from '../../constants'; +import { IacProjectType, iacRemediationTypes } from '../../constants'; import { State } from './scan/policy-engine'; export interface Result { @@ -22,9 +22,9 @@ export interface Result { policy: string; isPrivate: boolean; targetFilePath: string; - packageManager: string; + packageManager: IacProjectType | State.InputTypeEnum; path: string; - projectType: string; + projectType: IacProjectType | State.InputTypeEnum; ok: boolean; infrastructureAsCodeIssues: IacIssue[]; error?: string; @@ -56,7 +56,7 @@ export interface IacIssue { impact: string; msg: string; remediation?: Remediation; - subType: IacProjectType | State.InputTypeEnum; + subType: string; issue: string; publicId: string; title: string; @@ -69,14 +69,14 @@ export interface IacIssue { isGeneratedByCustomRule: boolean; path: string[]; policyEngineType?: string; - type?: string; + type?: IacProjectType | State.InputTypeEnum; compliance?: string[][]; description: string; } export interface Remediation { cloudformation?: string; - terraform: string; + terraform?: string; arm?: string; kubernetes?: string; } @@ -246,13 +246,15 @@ function vulnerabilitiesToIacIssues( vulnerabilities: Vulnerability[], ): IacIssue[] { return vulnerabilities.map((v) => { + const resolve = extractResolve(v); + return { severity: v.severity, - resolve: v.remediation, // potential needs to be deleted because it is supported only by the old format of our rules + resolve, impact: v.rule.description, msg: v.resource.formattedPath, remediation: { - terraform: v.remediation, // in the future we need to add logic that will add remediation only for the relevant field (based on file type) + [iacRemediationTypes[v.resource.kind] as string]: resolve, }, type: v.resource.kind, subType: v.resource.type, @@ -265,7 +267,7 @@ function vulnerabilitiesToIacIssues( iacDescription: { issue: v.rule.title, impact: v.rule.description, - resolve: v.remediation, + resolve, }, lineNumber: v.resource.line || -1, documentation: v.rule.documentation, // only works for rules available on snyk.io @@ -277,19 +279,30 @@ function vulnerabilitiesToIacIssues( }); } +function extractResolve(vulnerability: Vulnerability): string { + const newLineIdx = vulnerability.remediation.search(/\r?\n|\r/g); + return newLineIdx < 0 + ? vulnerability.remediation + : vulnerability.remediation.substring(0, newLineIdx); +} + // TODO: add correct mapping to our packageManger name (will probably be done in `snyk-iac-test`) -function resourcesToKind(resources: Resource[]): string { +function resourcesToKind( + resources: Resource[], +): IacProjectType | State.InputTypeEnum { for (const r of resources) { return r.kind; } - return ''; + return '' as IacProjectType | State.InputTypeEnum; } -function vulnerabilitiesToKind(vulnerabilities: Vulnerability[]): string { +function vulnerabilitiesToKind( + vulnerabilities: Vulnerability[], +): IacProjectType | State.InputTypeEnum { for (const v of vulnerabilities) { return v.resource.kind; } - return ''; + return '' as IacProjectType | State.InputTypeEnum; } function orgSettingsToMeta( diff --git a/src/lib/iac/test/v2/sarif.ts b/src/lib/iac/test/v2/sarif.ts index 4217278f2c..9e06de17e3 100644 --- a/src/lib/iac/test/v2/sarif.ts +++ b/src/lib/iac/test/v2/sarif.ts @@ -6,7 +6,7 @@ import * as upperFirst from 'lodash.upperfirst'; import * as camelCase from 'lodash.camelcase'; import { getVersion } from '../../../version'; -import { Results, TestOutput } from './scan/results'; +import { Results, TestOutput, Vulnerability } from './scan/results'; import { getIssueLevel } from '../../../formatters/sarif-output'; import { getRepositoryRoot } from '../../git'; @@ -73,6 +73,8 @@ function extractReportingDescriptor( const tags = ['security']; // switch to rules.labels once `snyk-iac-test` includes this info + const remediation = extractRemediation(vulnerability); + rules[vulnerability.rule.id] = { id: vulnerability.rule.id, name: upperFirst(camelCase(vulnerability.rule.title)).replace(/ /g, ''), @@ -85,8 +87,8 @@ function extractReportingDescriptor( text: vulnerability.rule.description, }, help: { - text: renderMarkdown(vulnerability.remediation), - markdown: vulnerability.remediation, + text: renderMarkdown(remediation), + markdown: remediation, }, defaultConfiguration: { level: getIssueLevel(vulnerability.severity), @@ -176,3 +178,10 @@ function mapSnykIacTestResultsToSarifResults( return result; } + +function extractRemediation(vulnerability: Vulnerability): string { + const newLineIdx = vulnerability.remediation.search(/\r?\n|\r/g); + return newLineIdx < 0 + ? vulnerability.remediation + : vulnerability.remediation.substring(0, newLineIdx); +} diff --git a/src/lib/iac/test/v2/scan/results.ts b/src/lib/iac/test/v2/scan/results.ts index b04a951567..2ac8338af2 100644 --- a/src/lib/iac/test/v2/scan/results.ts +++ b/src/lib/iac/test/v2/scan/results.ts @@ -62,11 +62,11 @@ export interface Rule { export interface Resource { id: string; - type: IacProjectType | PolicyEngineTypes.State.InputTypeEnum; + type: string; path?: any[]; formattedPath: string; file: string; - kind: string; + kind: IacProjectType | PolicyEngineTypes.State.InputTypeEnum; line?: number; column?: number; } diff --git a/test/jest/unit/iac/process-results/fixtures/experimental-json-output.json b/test/jest/unit/iac/process-results/fixtures/experimental-json-output.json index 49693e09d4..4cd0637507 100644 --- a/test/jest/unit/iac/process-results/fixtures/experimental-json-output.json +++ b/test/jest/unit/iac/process-results/fixtures/experimental-json-output.json @@ -38,11 +38,11 @@ "infrastructureAsCodeIssues": [ { "severity": "medium", - "resolve": "# Remediation Steps\n\n* Ensure that the [aws_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) is referenced in an [aws_flog_log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) `vpc_id` field.\n\n#### Example Configuration\n\n```hcl\nresource \"aws_vpc\" \"valid_vpc\" {\n # other required fields here\n}\n\nresource \"aws_flow_log\" \"test_flow_log\" {\n vpc_id = \"${aws_vpc.valid_vpc.id}\"\n # other required fields here\n}\n```\n", + "resolve": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field.", "impact": "VPC flow logging should be enabled. AWS VPC Flow Logs provide visibility into network traffic that traverses the AWS VPC.\nUsers can use the flow logs to detect anomalous traffic or insight during security workflows.\n", "msg": "resource.aws_vpc[mainvpc]", "remediation": { - "terraform": "# Remediation Steps\n\n* Ensure that the [aws_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) is referenced in an [aws_flog_log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) `vpc_id` field.\n\n#### Example Configuration\n\n```hcl\nresource \"aws_vpc\" \"valid_vpc\" {\n # other required fields here\n}\n\nresource \"aws_flow_log\" \"test_flow_log\" {\n vpc_id = \"${aws_vpc.valid_vpc.id}\"\n # other required fields here\n}\n```\n" + "terraform": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field." }, "type": "terraformconfig", "subType": "aws_vpc", @@ -57,7 +57,7 @@ "iacDescription": { "issue": "VPC flow logging should be enabled", "impact": "VPC flow logging should be enabled. AWS VPC Flow Logs provide visibility into network traffic that traverses the AWS VPC.\nUsers can use the flow logs to detect anomalous traffic or insight during security workflows.\n", - "resolve": "# Remediation Steps\n\n* Ensure that the [aws_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) is referenced in an [aws_flog_log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) `vpc_id` field.\n\n#### Example Configuration\n\n```hcl\nresource \"aws_vpc\" \"valid_vpc\" {\n # other required fields here\n}\n\nresource \"aws_flow_log\" \"test_flow_log\" {\n vpc_id = \"${aws_vpc.valid_vpc.id}\"\n # other required fields here\n}\n```\n" + "resolve": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field." }, "lineNumber": -1, "documentation": "https://snyk.io/security-rules/SNYK-CC-00151", @@ -68,11 +68,11 @@ }, { "severity": "medium", - "resolve": "# Remediation Steps\nEnsure that an [aws_default_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group) or [aws_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) `ingress` block does NOT contain the value `0.0.0.0/0` in the `cidr_blocks` (`ipv6_cidr_blocks` for ipv6) field.\n\n# Example configuration\n```hcl\nresource \"aws_security_group\" \"example\" {\n ingress {\n cidr_blocks = [10.0.0.0/16]\n from_port = 5900\n to_port = 5900\n # other required fields here\n }\n}\n```\n", + "resolve": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`.", "impact": "Configuring all VPC default security groups to restrict all traffic encourages least privilege security\ngroup development and mindful placement of AWS resources into security groups which in turn reduces the exposure of those resources.\n", "msg": "input.resource.aws_default_security_group[default].ingress[0].cidr_blocks[0]", "remediation": { - "terraform": "# Remediation Steps\nEnsure that an [aws_default_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group) or [aws_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) `ingress` block does NOT contain the value `0.0.0.0/0` in the `cidr_blocks` (`ipv6_cidr_blocks` for ipv6) field.\n\n# Example configuration\n```hcl\nresource \"aws_security_group\" \"example\" {\n ingress {\n cidr_blocks = [10.0.0.0/16]\n from_port = 5900\n to_port = 5900\n # other required fields here\n }\n}\n```\n" + "terraform": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`." }, "type": "terraformconfig", "subType": "aws_default_security_group", @@ -87,7 +87,7 @@ "iacDescription": { "issue": "VPC default security group allows unrestricted ingress traffic", "impact": "Configuring all VPC default security groups to restrict all traffic encourages least privilege security\ngroup development and mindful placement of AWS resources into security groups which in turn reduces the exposure of those resources.\n", - "resolve": "# Remediation Steps\nEnsure that an [aws_default_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group) or [aws_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) `ingress` block does NOT contain the value `0.0.0.0/0` in the `cidr_blocks` (`ipv6_cidr_blocks` for ipv6) field.\n\n# Example configuration\n```hcl\nresource \"aws_security_group\" \"example\" {\n ingress {\n cidr_blocks = [10.0.0.0/16]\n from_port = 5900\n to_port = 5900\n # other required fields here\n }\n}\n```\n" + "resolve": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`." }, "lineNumber": -1, "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-5", @@ -137,11 +137,11 @@ "infrastructureAsCodeIssues": [ { "severity": "medium", - "resolve": "# Remediation Steps\n\n* Ensure that the [aws_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) is referenced in an [aws_flog_log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) `vpc_id` field.\n\n#### Example Configuration\n\n```hcl\nresource \"aws_vpc\" \"valid_vpc\" {\n # other required fields here\n}\n\nresource \"aws_flow_log\" \"test_flow_log\" {\n vpc_id = \"${aws_vpc.valid_vpc.id}\"\n # other required fields here\n}\n```\n", + "resolve": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field.", "impact": "VPC flow logging should be enabled. AWS VPC Flow Logs provide visibility into network traffic that traverses the AWS VPC.\nUsers can use the flow logs to detect anomalous traffic or insight during security workflows.\n", "msg": "resource.aws_vpc[mainvpc]", "remediation": { - "terraform": "# Remediation Steps\n\n* Ensure that the [aws_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) is referenced in an [aws_flog_log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) `vpc_id` field.\n\n#### Example Configuration\n\n```hcl\nresource \"aws_vpc\" \"valid_vpc\" {\n # other required fields here\n}\n\nresource \"aws_flow_log\" \"test_flow_log\" {\n vpc_id = \"${aws_vpc.valid_vpc.id}\"\n # other required fields here\n}\n```\n" + "terraform": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field." }, "type": "terraformconfig", "subType": "aws_vpc", @@ -156,7 +156,7 @@ "iacDescription": { "issue": "VPC flow logging should be enabled", "impact": "VPC flow logging should be enabled. AWS VPC Flow Logs provide visibility into network traffic that traverses the AWS VPC.\nUsers can use the flow logs to detect anomalous traffic or insight during security workflows.\n", - "resolve": "# Remediation Steps\n\n* Ensure that the [aws_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) is referenced in an [aws_flog_log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) `vpc_id` field.\n\n#### Example Configuration\n\n```hcl\nresource \"aws_vpc\" \"valid_vpc\" {\n # other required fields here\n}\n\nresource \"aws_flow_log\" \"test_flow_log\" {\n vpc_id = \"${aws_vpc.valid_vpc.id}\"\n # other required fields here\n}\n```\n" + "resolve": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field." }, "lineNumber": 5, "documentation": "https://snyk.io/security-rules/SNYK-CC-00151", @@ -167,11 +167,11 @@ }, { "severity": "medium", - "resolve": "# Remediation Steps\nEnsure that an [aws_default_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group) or [aws_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) `ingress` block does NOT contain the value `0.0.0.0/0` in the `cidr_blocks` (`ipv6_cidr_blocks` for ipv6) field.\n\n# Example configuration\n```hcl\nresource \"aws_security_group\" \"example\" {\n ingress {\n cidr_blocks = [10.0.0.0/16]\n from_port = 5900\n to_port = 5900\n # other required fields here\n }\n}\n```\n", + "resolve": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`.", "impact": "Configuring all VPC default security groups to restrict all traffic encourages least privilege security\ngroup development and mindful placement of AWS resources into security groups which in turn reduces the exposure of those resources.\n", "msg": "input.resource.aws_default_security_group[default].ingress[0].cidr_blocks[0]", "remediation": { - "terraform": "# Remediation Steps\nEnsure that an [aws_default_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group) or [aws_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) `ingress` block does NOT contain the value `0.0.0.0/0` in the `cidr_blocks` (`ipv6_cidr_blocks` for ipv6) field.\n\n# Example configuration\n```hcl\nresource \"aws_security_group\" \"example\" {\n ingress {\n cidr_blocks = [10.0.0.0/16]\n from_port = 5900\n to_port = 5900\n # other required fields here\n }\n}\n```\n" + "terraform": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`." }, "type": "terraformconfig", "subType": "aws_default_security_group", @@ -186,7 +186,7 @@ "iacDescription": { "issue": "VPC default security group allows unrestricted ingress traffic", "impact": "Configuring all VPC default security groups to restrict all traffic encourages least privilege security\ngroup development and mindful placement of AWS resources into security groups which in turn reduces the exposure of those resources.\n", - "resolve": "# Remediation Steps\nEnsure that an [aws_default_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group) or [aws_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) `ingress` block does NOT contain the value `0.0.0.0/0` in the `cidr_blocks` (`ipv6_cidr_blocks` for ipv6) field.\n\n# Example configuration\n```hcl\nresource \"aws_security_group\" \"example\" {\n ingress {\n cidr_blocks = [10.0.0.0/16]\n from_port = 5900\n to_port = 5900\n # other required fields here\n }\n}\n```\n" + "resolve": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`." }, "lineNumber": 16, "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-5", diff --git a/test/jest/unit/iac/process-results/fixtures/experimental-sarif-output.json b/test/jest/unit/iac/process-results/fixtures/experimental-sarif-output.json index fd7ec081e5..ea8de95bbb 100644 --- a/test/jest/unit/iac/process-results/fixtures/experimental-sarif-output.json +++ b/test/jest/unit/iac/process-results/fixtures/experimental-sarif-output.json @@ -28,8 +28,8 @@ "text": "VPC flow logging should be enabled. AWS VPC Flow Logs provide visibility into network traffic that traverses the AWS VPC.\nUsers can use the flow logs to detect anomalous traffic or insight during security workflows.\n" }, "help": { - "text": "Remediation Steps\nEnsure that the https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc is referenced in an https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log vpc_id field.Example Configuration\nresource \"aws_vpc\" \"valid_vpc\" {\n # other required fields here\n}\n\nresource \"aws_flow_log\" \"test_flow_log\" {\n vpc_id = \"${aws_vpc.valid_vpc.id}\"\n # other required fields here\n}", - "markdown": "# Remediation Steps\n\n* Ensure that the [aws_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) is referenced in an [aws_flog_log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) `vpc_id` field.\n\n#### Example Configuration\n\n```hcl\nresource \"aws_vpc\" \"valid_vpc\" {\n # other required fields here\n}\n\nresource \"aws_flow_log\" \"test_flow_log\" {\n vpc_id = \"${aws_vpc.valid_vpc.id}\"\n # other required fields here\n}\n```\n" + "text": "Reference the aws_vpc in an aws_flog_log vpc_id field.", + "markdown": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field." }, "defaultConfiguration": { "level": "warning" @@ -54,8 +54,8 @@ "text": "Configuring all VPC default security groups to restrict all traffic encourages least privilege security\ngroup development and mindful placement of AWS resources into security groups which in turn reduces the exposure of those resources.\n" }, "help": { - "text": "Remediation Steps\nEnsure that an https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group or https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group ingress block does NOT contain the value 0.0.0.0/0 in the cidr_blocks (ipv6_cidr_blocks for ipv6) field.Example configuration\nresource \"aws_security_group\" \"example\" {\n ingress {\n cidr_blocks = [10.0.0.0/16]\n from_port = 5900\n to_port = 5900\n # other required fields here\n }\n}", - "markdown": "# Remediation Steps\nEnsure that an [aws_default_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group) or [aws_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) `ingress` block does NOT contain the value `0.0.0.0/0` in the `cidr_blocks` (`ipv6_cidr_blocks` for ipv6) field.\n\n# Example configuration\n```hcl\nresource \"aws_security_group\" \"example\" {\n ingress {\n cidr_blocks = [10.0.0.0/16]\n from_port = 5900\n to_port = 5900\n # other required fields here\n }\n}\n```\n" + "text": "Remove any invalid ingress block from the aws_security_group or aws_default_security_group.", + "markdown": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`." }, "defaultConfiguration": { "level": "warning" diff --git a/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results.json b/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results.json index da3b9a6e05..d53e589135 100644 --- a/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results.json +++ b/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results.json @@ -44,7 +44,7 @@ "documentation": "https://snyk.io/security-rules/SNYK-CC-00151" }, "message": "VPC flow logging should be enabled", - "remediation": "# Remediation Steps\n\n* Ensure that the [aws_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) is referenced in an [aws_flog_log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) `vpc_id` field.\n\n#### Example Configuration\n\n```hcl\nresource \"aws_vpc\" \"valid_vpc\" {\n # other required fields here\n}\n\nresource \"aws_flow_log\" \"test_flow_log\" {\n vpc_id = \"${aws_vpc.valid_vpc.id}\"\n # other required fields here\n}\n```\n", + "remediation": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field.", "severity": "medium", "ignored": false, "resource": { @@ -69,7 +69,7 @@ "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-5" }, "message": "Inbound traffic to VPC should be more restrictive", - "remediation": "# Remediation Steps\nEnsure that an [aws_default_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group) or [aws_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) `ingress` block does NOT contain the value `0.0.0.0/0` in the `cidr_blocks` (`ipv6_cidr_blocks` for ipv6) field.\n\n# Example configuration\n```hcl\nresource \"aws_security_group\" \"example\" {\n ingress {\n cidr_blocks = [10.0.0.0/16]\n from_port = 5900\n to_port = 5900\n # other required fields here\n }\n}\n```\n", + "remediation": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`.\n\nEnsure that an [aws_default_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group) or [aws_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) `ingress` block does NOT contain the value `0.0.0.0/0` in the `cidr_blocks` (`ipv6_cidr_blocks` for ipv6) field.\n\n# Example configuration\n```hcl\nresource \"aws_security_group\" \"example\" {\n ingress {\n cidr_blocks = [10.0.0.0/16]\n from_port = 5900\n to_port = 5900\n # other required fields here\n }\n}\n```\n", "severity": "medium", "ignored": false, "resource": { @@ -99,7 +99,7 @@ "documentation": "https://snyk.io/security-rules/SNYK-CC-00151" }, "message": "VPC flow logging should be enabled", - "remediation": "# Remediation Steps\n\n* Ensure that the [aws_vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) is referenced in an [aws_flog_log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) `vpc_id` field.\n\n#### Example Configuration\n\n```hcl\nresource \"aws_vpc\" \"valid_vpc\" {\n # other required fields here\n}\n\nresource \"aws_flow_log\" \"test_flow_log\" {\n vpc_id = \"${aws_vpc.valid_vpc.id}\"\n # other required fields here\n}\n```\n", + "remediation": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field.\n\n# Example Configuration\n\n```hcl\nresource \"aws_vpc\" \"valid_vpc\" {\n# other required fields here\n}\n\nresource \"aws_flow_log\" \"test_flow_log\" {\nvpc_id = \"${aws_vpc.valid_vpc.id}\"\n# other required fields here\n}\n```\n", "severity": "medium", "ignored": false, "resource": { @@ -126,7 +126,7 @@ "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-5" }, "message": "Inbound traffic to VPC should be more restrictive", - "remediation": "# Remediation Steps\nEnsure that an [aws_default_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group) or [aws_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) `ingress` block does NOT contain the value `0.0.0.0/0` in the `cidr_blocks` (`ipv6_cidr_blocks` for ipv6) field.\n\n# Example configuration\n```hcl\nresource \"aws_security_group\" \"example\" {\n ingress {\n cidr_blocks = [10.0.0.0/16]\n from_port = 5900\n to_port = 5900\n # other required fields here\n }\n}\n```\n", + "remediation": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`.\n\nEnsure that an [aws_default_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group) or [aws_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) `ingress` block does NOT contain the value `0.0.0.0/0` in the `cidr_blocks` (`ipv6_cidr_blocks` for ipv6) field.\n\n# Example configuration\n```hcl\nresource \"aws_security_group\" \"example\" {\n ingress {\n cidr_blocks = [10.0.0.0/16]\n from_port = 5900\n to_port = 5900\n # other required fields here\n }\n}\n```\n", "severity": "medium", "ignored": false, "resource": { diff --git a/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-text-output-data.json b/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-text-output-data.json index 659afc74e9..d68cd5fa60 100644 --- a/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-text-output-data.json +++ b/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-text-output-data.json @@ -13,11 +13,14 @@ ], "issue": "VPC flow logging should be enabled", "impact": "VPC flow logging should be enabled. AWS VPC Flow Logs provide visibility into network traffic that traverses the AWS VPC.\nUsers can use the flow logs to detect anomalous traffic or insight during security workflows.\n", - "resolve": "", + "resolve": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field.", + "remediation": { + "terraform": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field." + }, "documentation": "https://snyk.io/security-rules/SNYK-CC-00151" }, "targetFile": "plan.json", - "projectType": "aws_vpc" + "projectType": "terraformconfig" }, { "issue": { @@ -35,11 +38,14 @@ ], "issue": "VPC default security group allows unrestricted ingress traffic", "impact": "Configuring all VPC default security groups to restrict all traffic encourages least privilege security\ngroup development and mindful placement of AWS resources into security groups which in turn reduces the exposure of those resources.\n", - "resolve": "", + "resolve": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`.", + "remediation": { + "terraform": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`." + }, "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-5" }, "targetFile": "plan.json", - "projectType": "aws_default_security_group" + "projectType": "terraformconfig" }, { "issue": { @@ -53,11 +59,14 @@ ], "issue": "VPC flow logging should be enabled", "impact": "VPC flow logging should be enabled. AWS VPC Flow Logs provide visibility into network traffic that traverses the AWS VPC.\nUsers can use the flow logs to detect anomalous traffic or insight during security workflows.\n", - "resolve": "", + "resolve": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field.", + "remediation": { + "terraform": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field." + }, "documentation": "https://snyk.io/security-rules/SNYK-CC-00151" }, "targetFile": "vpc_group.tf", - "projectType": "aws_vpc" + "projectType": "terraformconfig" }, { "issue": { @@ -75,11 +84,14 @@ ], "issue": "VPC default security group allows unrestricted ingress traffic", "impact": "Configuring all VPC default security groups to restrict all traffic encourages least privilege security\ngroup development and mindful placement of AWS resources into security groups which in turn reduces the exposure of those resources.\n", - "resolve": "", + "resolve": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`.", + "remediation": { + "terraform": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`." + }, "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-5" }, "targetFile": "vpc_group.tf", - "projectType": "aws_default_security_group" + "projectType": "terraformconfig" } ] }, From a0f759552fc00f2979552b3938e92f8d296d6364 Mon Sep 17 00:00:00 2001 From: Ofek Atar Date: Mon, 5 Sep 2022 17:06:59 +0300 Subject: [PATCH 15/55] chore: Added short-width terminals support for text output --- src/lib/formatters/iac-output/text/utils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib/formatters/iac-output/text/utils.ts b/src/lib/formatters/iac-output/text/utils.ts index d795491e39..7060e24ed0 100644 --- a/src/lib/formatters/iac-output/text/utils.ts +++ b/src/lib/formatters/iac-output/text/utils.ts @@ -30,4 +30,6 @@ export const colors: IacOutputColors = { export const contentPadding = ' '.repeat(2); -export const maxLineWidth = 80; +export const maxLineWidth = process.stdout.columns + ? Math.min(process.stdout.columns, 80) + : 80; From b5833a27811128f6b174c276b16af55491b087dc Mon Sep 17 00:00:00 2001 From: Craig Furman Date: Mon, 5 Sep 2022 14:43:02 +0100 Subject: [PATCH 16/55] feat: custom message for IaC cloud context errors There will be a request-specific error in the debug log, but we lack the plumbing to propagate this up without that flag as far as I know. The message contains a hint to run again with debug logs for this reason. --- src/cli/commands/test/iac/local-execution/types.ts | 1 + src/lib/iac/test/v2/errors.ts | 2 ++ .../v2/local-cache/policy-engine/constants/utils.ts | 12 ++++++------ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/cli/commands/test/iac/local-execution/types.ts b/src/cli/commands/test/iac/local-execution/types.ts index 31aa6402cf..2e0006074e 100644 --- a/src/cli/commands/test/iac/local-execution/types.ts +++ b/src/cli/commands/test/iac/local-execution/types.ts @@ -387,6 +387,7 @@ export enum IaCErrorCodes { UnableToReadPath = 2113, NoLoadableInput = 2114, FailedToMakeResourcesResolvers = 2115, + ResourcesResolverError = 2116, FailedToShareResults = 2200, } diff --git a/src/lib/iac/test/v2/errors.ts b/src/lib/iac/test/v2/errors.ts index b154a33de1..661550741e 100644 --- a/src/lib/iac/test/v2/errors.ts +++ b/src/lib/iac/test/v2/errors.ts @@ -32,6 +32,8 @@ const snykIacTestErrorsUserMessages = { "The Snyk CLI couldn't find any valid IaC configuration files to scan", FailedToMakeResourcesResolvers: 'An error occurred preparing the requested cloud context. Please run the command again with the `-d` flag for more information.', + ResourcesResolverError: + 'An error occurred scanning cloud resources. Please run the command again with the `-d` flag for more information.', FailedToShareResults: 'Failed to upload the test results with the platform', }; diff --git a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts index 62b496e7a8..a9993e096a 100644 --- a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts +++ b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts @@ -1,11 +1,11 @@ import * as os from 'os'; -const policyEngineChecksums = `0cbcdc8f4a7652835355f010d5cb97597055577e624799428c62819d74773b7e snyk-iac-test_0.28.0_Windows_arm64.exe -28637249844c060dc950c6d3fdb31e1ff2d96bfe76291fb383d5c94ee2db7b26 snyk-iac-test_0.28.0_Linux_x86_64 -45629e08ff8c3bfc601773d38705c19ea3abc2b8c33ee7174c97eb5669aa73f9 snyk-iac-test_0.28.0_Linux_arm64 -5a5066edc9dc8daf61fe57f57e844cff59c91c0fdb70f3efda3fe8260f06e801 snyk-iac-test_0.28.0_Windows_x86_64.exe -db669ad313d222184e07c02f3540b06c62de283ef2e57a75ee1df4116f1831a3 snyk-iac-test_0.28.0_Darwin_x86_64 -eb0b99c469eb31f930852466bb1e8b9e576a0bf22ea17dc951762f824009c18a snyk-iac-test_0.28.0_Darwin_arm64 +const policyEngineChecksums = `11bcf635e209023478f4291fe29e4aa5e4e719dde54dc0e333bae7a626ed6b6d snyk-iac-test_0.29.0_Linux_arm64 +557d4ab7b3c23b34ed81c31109140833dcc4863946774a4ba72d7b18800d4d34 snyk-iac-test_0.29.0_Darwin_x86_64 +7f5db81dad9f7ae4d80c472757b67c37ab29bbb9a18174b30c3354e494fc1505 snyk-iac-test_0.29.0_Linux_x86_64 +89de8e29d0aca232870bd1896aa5c66abb7917566de22d69ff847402b9566690 snyk-iac-test_0.29.0_Darwin_arm64 +cc9d1b48530b69774162e06774fef930e91fb3fe4be8f73e8605a2a6ac7eedfb snyk-iac-test_0.29.0_Windows_x86_64.exe +f1ea52361d5409ad0e2a492425a70c31797d91c999aa510eb7e99f27f575f0a8 snyk-iac-test_0.29.0_Windows_arm64.exe `; export const policyEngineVersion = getPolicyEngineVersion(); From e712369005d8ea97b8059089e160247a4aacd884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Scha=CC=88fer?= <101886095+PeterSchafer@users.noreply.github.com> Date: Thu, 1 Sep 2022 18:44:34 +0200 Subject: [PATCH 17/55] =?UTF-8?q?chore:=20copy=20embedded=20file=20logic?= =?UTF-8?q?=20over=20from=20=E2=80=98cliv2-extensions-init=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: add go license Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: remove placeholder licnese file Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: add simple —about implementation … … combining —about from cliv1 and local output Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: add readme and remove license file Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: update git ignore Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: add generation of 3rd party licenses to Makefile Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: adapt output format of —about Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: adapt go-license usage Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: print license files Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: change installation of go-license Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: fix issue when cross compiling Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: adding manual download for missing licenses Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> --- cliv2/.gitignore | 1 + cliv2/Makefile | 11 +++- cliv2/cmd/cliv2/main_test.go | 2 + cliv2/internal/cliv2/cliv2.go | 36 ++++++++++ cliv2/internal/embedded/_data/README.md | 1 + cliv2/internal/embedded/file.go | 88 +++++++++++++++++++++++++ cliv2/scripts/prepare_licenses.sh | 26 ++++++++ 7 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 cliv2/internal/embedded/_data/README.md create mode 100644 cliv2/internal/embedded/file.go create mode 100755 cliv2/scripts/prepare_licenses.sh diff --git a/cliv2/.gitignore b/cliv2/.gitignore index 378ccbc090..fbd4af54ba 100644 --- a/cliv2/.gitignore +++ b/cliv2/.gitignore @@ -10,3 +10,4 @@ _cache .dccache .vscode bin +internal/embedded/_data diff --git a/cliv2/Makefile b/cliv2/Makefile index 50d5f06815..41250da081 100644 --- a/cliv2/Makefile +++ b/cliv2/Makefile @@ -2,6 +2,8 @@ GOCMD = go GOOS = $(shell go env GOOS) GOARCH = $(shell go env GOARCH) +GOHOSTOS = $(shell go env GOHOSTOS) +GOHOSTARCH = $(shell go env GOHOSTARCH) HASH = sha HASH_ALGORITHM = 256 CLI_V2_VERSION_TAG = 2.0.0-prerelease @@ -79,6 +81,7 @@ TEST_SNYK_EXECUTABLE_PATH=$(BUILD_DIR)/$(V2_EXECUTABLE_NAME) TEST_EXECUTABLE_NAME = $(TEST_NAME)$(_SEPARATOR)$(V2_PLATFORM_STRING)$(_EXE_POSTFIX) SIGN_SCRIPT = sign_$(_GO_OS).sh ISSIGNED_SCRIPT = issigned_$(_GO_OS).sh +EMBEDDED_DATA_DIR = $(WORKING_DIR)/internal/embedded/_data # some make file variables LOG_PREFIX = -- @@ -140,7 +143,7 @@ dependencies: $(V1_DIRECTORY)/$(V1_EXECUTABLE_NAME) $(V1_DIRECTORY)/$(V1_EXECUTA # prepare the workspace and cache global parameters .PHONY: configure -configure: $(V2_DIRECTORY)/cliv2.version $(CACHE_DIR) $(CACHE_DIR)/version.mk $(CACHE_DIR)/variables.mk $(V1_DIRECTORY)/$(V1_EMBEDDED_FILE_OUTPUT) dependencies +configure: $(V2_DIRECTORY)/cliv2.version $(CACHE_DIR) $(CACHE_DIR)/version.mk $(CACHE_DIR)/variables.mk $(V1_DIRECTORY)/$(V1_EMBEDDED_FILE_OUTPUT) dependencies $(CACHE_DIR)/prepare-3rd-party-licenses $(BUILD_DIR)/$(V2_EXECUTABLE_NAME): $(BUILD_DIR) $(SRCS) @echo "$(LOG_PREFIX) Building ( $(BUILD_DIR)/$(V2_EXECUTABLE_NAME) )" @@ -174,6 +177,11 @@ $(WORKING_DIR)/internal/httpauth/generated/httpauth_generated_mock.go: $(WORKING_DIR)/internal/httpauth/generated/spnego_generated_mock.go: @$(GOCMD) generate ./internal/httpauth/ + +$(CACHE_DIR)/prepare-3rd-party-licenses: + @echo "$(LOG_PREFIX) Preparing 3rd Party Licenses" + @GOOS=$(GOHOSTOS) GOARCH=$(GOHOSTARCH) scripts/prepare_licenses.sh > $(CACHE_DIR)/prepare-3rd-party-licenses + .PHONY: generate generate: $(WORKING_DIR)/internal/httpauth/generated/httpauth_generated_mock.go $(WORKING_DIR)/internal/httpauth/generated/spnego_generated_mock.go @@ -227,6 +235,7 @@ clean: @rm -f $(V1_DIRECTORY)/$(V1_EMBEDDED_FILE_OUTPUT) @rm -f $(V1_DIRECTORY)/cliv1.version @rm -f $(V2_DIRECTORY)/cliv2.version + @rm -f -r $(EMBEDDED_DATA_DIR)/licenses .PHONY: install install: diff --git a/cliv2/cmd/cliv2/main_test.go b/cliv2/cmd/cliv2/main_test.go index d19a693def..4360cad65d 100644 --- a/cliv2/cmd/cliv2/main_test.go +++ b/cliv2/cmd/cliv2/main_test.go @@ -33,6 +33,8 @@ func Test_MainWithErrorCode_no_cache(t *testing.T) { assert.Equal(t, mainErr, 0) assert.DirExists(t, cacheDirectory) + + os.RemoveAll(cacheDirectory) } func Test_GetConfiguration(t *testing.T) { diff --git a/cliv2/internal/cliv2/cliv2.go b/cliv2/internal/cliv2/cliv2.go index d0d153385d..46f46c2d9d 100644 --- a/cliv2/internal/cliv2/cliv2.go +++ b/cliv2/internal/cliv2/cliv2.go @@ -48,6 +48,7 @@ const SNYK_CA_CERTIFICATE_LOCATION_ENV = "NODE_EXTRA_CA_CERTS" const ( V1_DEFAULT Handler = iota V2_VERSION Handler = iota + V2_ABOUT Handler = iota ) //go:embed cliv2.version @@ -134,6 +135,37 @@ func (c *CLI) commandVersion(passthroughArgs []string) int { } } +func (c *CLI) commandAbout(wrapperProxyPort int, fullPathToCert string, passthroughArgs []string) int { + + returnCode := c.executeV1Default(wrapperProxyPort, fullPathToCert, passthroughArgs) + if returnCode != SNYK_EXIT_CODE_OK { + return returnCode + } + + separator := "\n+-+-+-+-+-+-+\n\n" + + allEmbeddedFiles := embedded.ListFiles() + for i := range allEmbeddedFiles { + f := &allEmbeddedFiles[i] + path := f.Path() + + if strings.Contains(path, "licenses") { + size := f.Size() + data := make([]byte, size) + _, err := f.Read(data) + if err != nil { + continue + } + + fmt.Printf("Package: %s \n", strings.ReplaceAll(strings.ReplaceAll(path, "/licenses/", ""), "/"+f.Name(), "")) + fmt.Println(string(data)) + fmt.Println(separator) + } + } + + return SNYK_EXIT_CODE_OK +} + func determineHandler(passthroughArgs []string) Handler { result := V1_DEFAULT @@ -141,6 +173,8 @@ func determineHandler(passthroughArgs []string) Handler { utils.Contains(passthroughArgs, "-v") || utils.Contains(passthroughArgs, "version") { result = V2_VERSION + } else if utils.Contains(passthroughArgs, "--about") { + result = V2_ABOUT } return result @@ -248,6 +282,8 @@ func (c *CLI) Execute(wrapperProxyPort int, fullPathToCert string, passthroughAr switch { case handler == V2_VERSION: returnCode = c.commandVersion(passthroughArgs) + case handler == V2_ABOUT: + returnCode = c.commandAbout(wrapperProxyPort, fullPathToCert, passthroughArgs) default: returnCode = c.executeV1Default(wrapperProxyPort, fullPathToCert, passthroughArgs) } diff --git a/cliv2/internal/embedded/_data/README.md b/cliv2/internal/embedded/_data/README.md new file mode 100644 index 0000000000..78f7dc8a27 --- /dev/null +++ b/cliv2/internal/embedded/_data/README.md @@ -0,0 +1 @@ +This directory includes files that'll be compiled into the final application. diff --git a/cliv2/internal/embedded/file.go b/cliv2/internal/embedded/file.go new file mode 100644 index 0000000000..7dbaea768c --- /dev/null +++ b/cliv2/internal/embedded/file.go @@ -0,0 +1,88 @@ +package embedded + +import ( + "embed" + "io/fs" + "math" + "os" + "path/filepath" + "strings" +) + +const ( + rootDirectory string = "_data" +) + +//go:embed _data +var data embed.FS + +type File struct { + name string + path string + cachedData []byte +} + +func ListFiles() []File { + var result []File + + fs.WalkDir(data, rootDirectory, func(path string, d fs.DirEntry, err error) error { + if !d.IsDir() { + f := File{ + name: d.Name(), + path: path, + } + result = append(result, f) + } + + return err + }) + + return result +} + +func (f *File) data() ([]byte, error) { + var err error + if f.cachedData == nil { + f.cachedData, err = data.ReadFile(f.path) + } + return f.cachedData, err +} + +func (f *File) Read(p []byte) (n int, err error) { + tmp, err := f.data() + n = int(math.Min(float64(len(tmp)), float64(len(p)))) + copy(p, tmp) + return n, err +} + +func (f *File) Size() int { + d, _ := f.data() + return len(d) +} + +func (f *File) Name() string { + return f.name +} + +func (f *File) Path() string { + return strings.Replace(f.path, rootDirectory, "", 1) +} + +func (f *File) SaveToLocalFilesystem(destPath string, fileMode fs.FileMode) (err error) { + size := f.Size() + data := make([]byte, size) + + _, err = f.Read(data) + if err == nil { + folder := filepath.Dir(destPath) + _, err = os.Stat(folder) + if os.IsNotExist(err) { + err = os.MkdirAll(folder, fileMode) + } + } + + if err == nil { + err = os.WriteFile(destPath, data, fileMode) + } + return err +} diff --git a/cliv2/scripts/prepare_licenses.sh b/cliv2/scripts/prepare_licenses.sh new file mode 100755 index 0000000000..62473f19c4 --- /dev/null +++ b/cliv2/scripts/prepare_licenses.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail + +function manualLicenseDownload +{ + mkdir -p "./internal/embedded/_data/licenses/$2" + curl -L --progress-bar --fail "$1" > "./internal/embedded/_data/licenses/$2/LICENSE" +} + +# try to find all licenses via the go.mod file +export GOBIN=$(pwd)/_cache +go install github.com/google/go-licenses@latest +PATH="$PATH:$GOBIN" go-licenses save ./... --save_path=./internal/embedded/_data/licenses --force --ignore github.com/snyk/cli/cliv2/ + +manualLicenseDownload "https://raw.githubusercontent.com/davecgh/go-spew/master/LICENSE" github.com/davecgh/go-spew +manualLicenseDownload "https://raw.githubusercontent.com/alexbrainman/sspi/master/LICENSE" github.com/alexbrainman/sspi +manualLicenseDownload "https://raw.githubusercontent.com/pmezard/go-difflib/master/LICENSE" github.com/pmezard/go-difflib +manualLicenseDownload "https://raw.githubusercontent.com/go-yaml/yaml/v3.0.1/LICENSE" gopkg.in/yaml.v3 +manualLicenseDownload "https://go.dev/LICENSE?m=text" go.dev + +# clean up and print result +pushd . > /dev/null +cd ./internal/embedded/_data/licenses +find . -type f -name '*.*' -delete +find . -type f -name '*' -exec echo " {}" \; +popd > /dev/null From 528385817750e4228112fc60dc954b177b3b3855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Scha=CC=88fer?= <101886095+PeterSchafer@users.noreply.github.com> Date: Mon, 5 Sep 2022 18:42:07 +0200 Subject: [PATCH 18/55] =?UTF-8?q?chore:=20copy=20embedded=20file=20logic?= =?UTF-8?q?=20over=20from=20=E2=80=98cliv2-extensions-init=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: add go license Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: remove placeholder licnese file Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: add simple —about implementation … … combining —about from cliv1 and local output Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: add readme and remove license file Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: update git ignore Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: add generation of 3rd party licenses to Makefile Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: adapt output format of —about Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: adapt go-license usage Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: print license files Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: change installation of go-license Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: fix issue when cross compiling Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: adding manual download for missing licenses Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: remove version prefix “2.0.0-prerelease” Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> --- cliv2/Makefile | 2 +- cliv2/internal/cliv2/cliv2.go | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cliv2/Makefile b/cliv2/Makefile index 41250da081..4859d7ba16 100644 --- a/cliv2/Makefile +++ b/cliv2/Makefile @@ -6,7 +6,7 @@ GOHOSTOS = $(shell go env GOHOSTOS) GOHOSTARCH = $(shell go env GOHOSTARCH) HASH = sha HASH_ALGORITHM = 256 -CLI_V2_VERSION_TAG = 2.0.0-prerelease +CLI_V2_VERSION_TAG = CLI_V1_VERSION_TAG = CLI_V1_LOCATION = diff --git a/cliv2/internal/cliv2/cliv2.go b/cliv2/internal/cliv2/cliv2.go index 46f46c2d9d..dd9a6e4bb6 100644 --- a/cliv2/internal/cliv2/cliv2.go +++ b/cliv2/internal/cliv2/cliv2.go @@ -110,7 +110,11 @@ func (c *CLI) ExtractV1Binary() error { } func (c *CLI) GetFullVersion() string { - return c.v2Version + "." + c.v1Version + if len(c.v2Version) > 0 { + return c.v2Version + "." + c.v1Version + } else { + return c.v1Version + } } func (c *CLI) GetIntegrationName() string { From b9c1a10a667fc6c9b2920a170b44e333fb2f6cd1 Mon Sep 17 00:00:00 2001 From: Craig Furman Date: Tue, 6 Sep 2022 08:54:43 +0100 Subject: [PATCH 19/55] feat: cloud context for IaC tests Undocumented, and does nothing when not combined with `--experimental`. Docs will be added when this moves out of experimental usage. --- .../commands/test/iac/local-execution/types.ts | 1 + .../commands/test/iac/v2/assert-iac-options.ts | 17 +++++++++++++++++ src/cli/commands/test/iac/v2/index.ts | 2 ++ src/lib/iac/test/v2/scan/index.ts | 4 ++++ src/lib/iac/test/v2/types.ts | 1 + 5 files changed, 25 insertions(+) diff --git a/src/cli/commands/test/iac/local-execution/types.ts b/src/cli/commands/test/iac/local-execution/types.ts index 2e0006074e..2e75318f94 100644 --- a/src/cli/commands/test/iac/local-execution/types.ts +++ b/src/cli/commands/test/iac/local-execution/types.ts @@ -203,6 +203,7 @@ export type IaCTestFlags = Pick< path?: string; // Allows the caller to provide the path to a WASM bundle. rules?: string; + 'cloud-context'?: string; // Tags and attributes 'project-tags'?: string; 'project-environment'?: string; diff --git a/src/cli/commands/test/iac/v2/assert-iac-options.ts b/src/cli/commands/test/iac/v2/assert-iac-options.ts index 506c296e56..7a03fc3a10 100644 --- a/src/cli/commands/test/iac/v2/assert-iac-options.ts +++ b/src/cli/commands/test/iac/v2/assert-iac-options.ts @@ -29,6 +29,7 @@ const keys: (keyof IaCTestFlags)[] = [ 'experimental', 'var-file', 'detectionDepth', + 'cloud-context', // PolicyOptions 'ignore-policy', 'policy-path', @@ -57,6 +58,10 @@ export function assertIacV2Options(options: IaCTestFlags): void { if (options.scan) { assertTerraformPlanModes(options.scan as string); } + + if (options['cloud-context']) { + assertCloudContextOptions(options['cloud-context']); + } } function assertSeverityOptions(severity: SEVERITY) { @@ -79,3 +84,15 @@ function assertVarFileOptions(filePath: string) { throw new FlagValueError('var-file', filePath, '.tfvars file'); } } + +function assertCloudContextOptions(cloudContext: string) { + const validCloudContextOptions = ['aws']; + + if (!validCloudContextOptions.includes(cloudContext)) { + throw new FlagValueError( + 'cloud-context', + cloudContext, + validCloudContextOptions.join(', '), + ); + } +} diff --git a/src/cli/commands/test/iac/v2/index.ts b/src/cli/commands/test/iac/v2/index.ts index 14373b8838..c065a071e5 100644 --- a/src/cli/commands/test/iac/v2/index.ts +++ b/src/cli/commands/test/iac/v2/index.ts @@ -60,6 +60,7 @@ async function prepareTestConfig( const policy = await findAndLoadPolicy(process.cwd(), 'iac', options); const scan = options.scan ?? 'resource-changes'; const varFile = options['var-file']; + const cloudContext = getFlag(options, 'cloud-context'); return { paths, @@ -78,6 +79,7 @@ async function prepareTestConfig( scan, varFile, depthDetection, + cloudContext, }; } diff --git a/src/lib/iac/test/v2/scan/index.ts b/src/lib/iac/test/v2/scan/index.ts index 088e84e5a6..9ab3ad66d4 100644 --- a/src/lib/iac/test/v2/scan/index.ts +++ b/src/lib/iac/test/v2/scan/index.ts @@ -156,6 +156,10 @@ function processFlags( flags.push('-var-file', options.varFile); } + if (options.cloudContext) { + flags.push('-cloud-context', options.cloudContext); + } + return flags; } diff --git a/src/lib/iac/test/v2/types.ts b/src/lib/iac/test/v2/types.ts index b44652801b..769aa8edac 100644 --- a/src/lib/iac/test/v2/types.ts +++ b/src/lib/iac/test/v2/types.ts @@ -19,4 +19,5 @@ export interface TestConfig { scan: string; varFile?: string; depthDetection?: number; + cloudContext?: string; } From 1be5da42d27c12973b0d0119d98f2d2fed900e79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Scha=CC=88fer?= <101886095+PeterSchafer@users.noreply.github.com> Date: Tue, 6 Sep 2022 13:17:39 +0200 Subject: [PATCH 20/55] chore: install git on alpine and re-enable test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> --- .circleci/config.yml | 2 +- test/jest/acceptance/iac/file-output.spec.ts | 52 +++++++++----------- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f4b046df8a..154a0de6fc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -383,7 +383,7 @@ jobs: - run: name: Installing Node.js + other test dependencies command: | - apk add --update nodejs npm bash maven + apk add --update nodejs npm bash maven git - setup_npm: npm_cache_directory: /home/circleci/.npm npm_global_sudo: false diff --git a/test/jest/acceptance/iac/file-output.spec.ts b/test/jest/acceptance/iac/file-output.spec.ts index 080dea7d65..c7a565bb5c 100644 --- a/test/jest/acceptance/iac/file-output.spec.ts +++ b/test/jest/acceptance/iac/file-output.spec.ts @@ -85,36 +85,28 @@ describe('iac test --sarif-file-output', () => { expect(startLine).not.toEqual(-1); }); - if ( - process.env.TEST_SNYK_COMMAND && - process.env.TEST_SNYK_COMMAND.includes('alpine') - ) { - // This test is temporarily skipped on Alpine Linux. - it.skip('returns the correct paths for provided path', async () => {}); - } else { - it('returns the correct paths for provided path', async () => { - const sarifOutputFilename = path.join(__dirname, `${uuidv4()}.sarif`); - const { stdout } = await run( - `snyk iac test ./iac/file-output/sg_open_ssh.tf --sarif-file-output=${sarifOutputFilename}`, - ); - expect(stdout).toMatch('Organization:'); - - const outputFileContents = readFileSync(sarifOutputFilename, 'utf-8'); - unlinkSync(sarifOutputFilename); - const jsonObj = JSON.parse(outputFileContents); - const actualPhysicalLocation = - jsonObj?.runs?.[0].results[0].locations[0].physicalLocation - .artifactLocation.uri; - const actualProjectRoot = - jsonObj?.runs?.[0].originalUriBaseIds.PROJECTROOT.uri; - expect(actualPhysicalLocation).toEqual( - 'test/fixtures/iac/file-output/sg_open_ssh.tf', - ); - expect(actualProjectRoot).toEqual( - pathToFileURL(path.join(path.resolve(''), '/')).href, - ); - }); - } + it('returns the correct paths for provided path', async () => { + const sarifOutputFilename = path.join(__dirname, `${uuidv4()}.sarif`); + const { stdout } = await run( + `snyk iac test ./iac/file-output/sg_open_ssh.tf --sarif-file-output=${sarifOutputFilename}`, + ); + expect(stdout).toMatch('Organization:'); + + const outputFileContents = readFileSync(sarifOutputFilename, 'utf-8'); + unlinkSync(sarifOutputFilename); + const jsonObj = JSON.parse(outputFileContents); + const actualPhysicalLocation = + jsonObj?.runs?.[0].results[0].locations[0].physicalLocation + .artifactLocation.uri; + const actualProjectRoot = + jsonObj?.runs?.[0].originalUriBaseIds.PROJECTROOT.uri; + expect(actualPhysicalLocation).toEqual( + 'test/fixtures/iac/file-output/sg_open_ssh.tf', + ); + expect(actualProjectRoot).toEqual( + pathToFileURL(path.join(path.resolve(''), '/')).href, + ); + }); it('does not include file content in analytics logs', async () => { const { stdout, exitCode } = await run( From 47af5cab7473a742d83b59ae7016ba78e63763b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramon=20R=C3=BCttimann?= Date: Tue, 6 Sep 2022 14:19:01 +0200 Subject: [PATCH 21/55] feat: container Go binary scan Bumps the version of the docker-plugin to support trimmed, stripped and Cgo binaries. See [snyk-docker-plugin #447](https://github.com/snyk/snyk-docker-plugin/pull/447) for more info. --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index de3d667d55..af135ec344 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,7 +66,7 @@ "semver": "^6.0.0", "snyk-config": "4.0.0", "snyk-cpp-plugin": "2.20.0", - "snyk-docker-plugin": "^5.3.2", + "snyk-docker-plugin": "^5.4.0", "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.22.2", "snyk-module": "3.1.0", @@ -16512,9 +16512,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/snyk-docker-plugin": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.3.2.tgz", - "integrity": "sha512-QIbQD9sA6hkadiZaO/8nhyXFTWew5P25MbTb53pCjB7b58X+u8skaoYKIFzWpqjSumf0/cq0R01E0Sxvykvc3Q==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.0.tgz", + "integrity": "sha512-9aba6EJqmbJBfYUoYMbqz/ghV2xt02hl8LbFC8OzooXIyu4z72BBRUSfs3geRuLnhSYUIp4etzsOryCuqQdG2g==", "dependencies": { "@snyk/composer-lockfile-parser": "^1.4.1", "@snyk/dep-graph": "^2.3.0", @@ -32919,9 +32919,9 @@ } }, "snyk-docker-plugin": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.3.2.tgz", - "integrity": "sha512-QIbQD9sA6hkadiZaO/8nhyXFTWew5P25MbTb53pCjB7b58X+u8skaoYKIFzWpqjSumf0/cq0R01E0Sxvykvc3Q==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.0.tgz", + "integrity": "sha512-9aba6EJqmbJBfYUoYMbqz/ghV2xt02hl8LbFC8OzooXIyu4z72BBRUSfs3geRuLnhSYUIp4etzsOryCuqQdG2g==", "requires": { "@snyk/composer-lockfile-parser": "^1.4.1", "@snyk/dep-graph": "^2.3.0", diff --git a/package.json b/package.json index a932c4b6fe..2edddb4484 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "semver": "^6.0.0", "snyk-config": "4.0.0", "snyk-cpp-plugin": "2.20.0", - "snyk-docker-plugin": "^5.3.2", + "snyk-docker-plugin": "^5.4.0", "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.22.2", "snyk-module": "3.1.0", From d62079575a218d8fce8836c4a758afdae4dd5526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Scha=CC=88fer?= <101886095+PeterSchafer@users.noreply.github.com> Date: Wed, 7 Sep 2022 14:42:05 +0200 Subject: [PATCH 22/55] chore: upgrade danger from 10.7.1 to 10.9.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> --- package-lock.json | 540 +++++++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 292 insertions(+), 250 deletions(-) diff --git a/package-lock.json b/package-lock.json index af135ec344..ac3b61b5cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -104,7 +104,7 @@ "conventional-changelog-cli": "^2.2.2", "copy-webpack-plugin": "^9.0.1", "cross-spawn": "^6.0.5", - "danger": "10.7.1", + "danger": "10.9.0", "depcheck": "^1.4.3", "eslint": "6.8.0", "eslint-config-prettier": "^6.1.0", @@ -598,6 +598,14 @@ "regenerator-runtime": "^0.13.4" } }, + "node_modules/@babel/polyfill/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true + }, "node_modules/@babel/template": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", @@ -1709,26 +1717,19 @@ "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" }, "node_modules/@octokit/openapi-types": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-9.7.0.tgz", - "integrity": "sha512-TUJ16DJU8mekne6+KVcMV5g6g/rJlrnIKn7aALG9QrNpnEipFc1xjoarh0PKaAWf2Hf+HwthRKYt+9mCm5RsRg==" + "version": "12.11.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", + "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==" }, "node_modules/@octokit/plugin-paginate-rest": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz", - "integrity": "sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==", - "dev": true, - "dependencies": { - "@octokit/types": "^2.0.1" - } - }, - "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", - "dev": true, + "version": "2.21.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", + "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", "dependencies": { - "@types/node": ">= 8" + "@octokit/types": "^6.40.0" + }, + "peerDependencies": { + "@octokit/core": ">=2" } }, "node_modules/@octokit/plugin-request-log": { @@ -1740,22 +1741,15 @@ } }, "node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz", - "integrity": "sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==", - "dev": true, + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", + "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", "dependencies": { - "@octokit/types": "^2.0.1", + "@octokit/types": "^6.39.0", "deprecation": "^2.3.1" - } - }, - "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", - "dev": true, - "dependencies": { - "@types/node": ">= 8" + }, + "peerDependencies": { + "@octokit/core": ">=3" } }, "node_modules/@octokit/request": { @@ -1807,35 +1801,22 @@ "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" }, "node_modules/@octokit/rest": { - "version": "16.43.2", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.2.tgz", - "integrity": "sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ==", - "dev": true, + "version": "18.12.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz", + "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", "dependencies": { - "@octokit/auth-token": "^2.4.0", - "@octokit/plugin-paginate-rest": "^1.1.1", - "@octokit/plugin-request-log": "^1.0.0", - "@octokit/plugin-rest-endpoint-methods": "2.4.0", - "@octokit/request": "^5.2.0", - "@octokit/request-error": "^1.0.2", - "atob-lite": "^2.0.0", - "before-after-hook": "^2.0.0", - "btoa-lite": "^1.0.0", - "deprecation": "^2.0.0", - "lodash.get": "^4.4.2", - "lodash.set": "^4.3.2", - "lodash.uniq": "^4.5.0", - "octokit-pagination-methods": "^1.1.0", - "once": "^1.4.0", - "universal-user-agent": "^4.0.0" + "@octokit/core": "^3.5.1", + "@octokit/plugin-paginate-rest": "^2.16.8", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^5.12.0" } }, "node_modules/@octokit/types": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.25.0.tgz", - "integrity": "sha512-bNvyQKfngvAd/08COlYIN54nRgxskmejgywodizQNyiKoXmWRAjKup2/LYwm+T9V0gsKH6tuld1gM0PzmOiB4Q==", + "version": "6.41.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", + "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", "dependencies": { - "@octokit/openapi-types": "^9.5.0" + "@octokit/openapi-types": "^12.11.0" } }, "node_modules/@open-policy-agent/opa-wasm": { @@ -2137,14 +2118,6 @@ "tslib": "^1.10.0" } }, - "node_modules/@snyk/docker-registry-v2-client/node_modules/parse-link-header": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-2.0.0.tgz", - "integrity": "sha512-xjU87V0VyHZybn2RrCX5TIFGxTVZE6zqqZWMPlIKiSKuWh/X5WZdt+w1Ki1nXB+8L/KtL+nZ4iq+sfI6MrhhMw==", - "dependencies": { - "xtend": "~4.0.1" - } - }, "node_modules/@snyk/fast-glob": { "version": "3.2.6-patch", "resolved": "https://registry.npmjs.org/@snyk/fast-glob/-/fast-glob-3.2.6-patch.tgz", @@ -4228,7 +4201,7 @@ "node_modules/atob-lite": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz", - "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=", + "integrity": "sha512-LEeSAWeh2Gfa2FtlQE1shxQ8zi5F9GHarrGKz08TMdODD5T4eH6BMsvtnhbWZ+XQn+Gb6om/917ucvRu7l7ukw==", "dev": true }, "node_modules/aws-sign2": { @@ -4679,7 +4652,7 @@ "node_modules/btoa-lite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", - "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=", + "integrity": "sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA==", "dev": true }, "node_modules/buffer": { @@ -5826,12 +5799,14 @@ } }, "node_modules/core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "deprecated": "core-js@<3.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.", - "dev": true, - "hasInstallScript": true + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.25.0.tgz", + "integrity": "sha512-CVU1xvJEfJGhyCpBrzzzU1kjCfgsGUxhEvwUV2e/cOedYWHdmluamx+knDnmhqALddMG16fZvIqvs9aijsHHaA==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } }, "node_modules/core-util-is": { "version": "1.0.2", @@ -6008,9 +5983,9 @@ "dev": true }, "node_modules/danger": { - "version": "10.7.1", - "resolved": "https://registry.npmjs.org/danger/-/danger-10.7.1.tgz", - "integrity": "sha512-lKyWrWxNxtSfLSsOqse+O9MOrxa++a0kHEBxrgCBvjF36EjNuInuvY06omUTDGdIy6VEbDQRoGeQFIBauj8sMA==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/danger/-/danger-10.9.0.tgz", + "integrity": "sha512-eEWQAaIPfWSfzlQiFx+w9fWuP3jwq8VAV9W22EZRxfmCBnkdDa5aN0Akr7lzfCKudzy+4uEmIGUtxnYeFgTthQ==", "dev": true, "dependencies": { "@babel/polyfill": "^7.2.5", @@ -6026,7 +6001,7 @@ "https-proxy-agent": "^2.2.1", "hyperlinker": "^1.0.0", "json5": "^2.1.0", - "jsonpointer": "^4.0.1", + "jsonpointer": "^5.0.0", "jsonwebtoken": "^8.4.0", "lodash.find": "^4.6.0", "lodash.includes": "^4.3.0", @@ -6037,13 +6012,13 @@ "memfs-or-file-map-to-github-branch": "^1.1.0", "micromatch": "^4.0.4", "node-cleanup": "^2.1.2", - "node-fetch": "2.6.1", + "node-fetch": "^2.6.7", "override-require": "^1.1.1", "p-limit": "^2.1.0", "parse-diff": "^0.7.0", "parse-git-config": "^2.0.3", "parse-github-url": "^1.0.2", - "parse-link-header": "^1.0.1", + "parse-link-header": "^2.0.0", "pinpoint": "^1.1.0", "prettyjson": "^1.2.1", "readline-sync": "^1.4.9", @@ -6062,6 +6037,58 @@ "danger-runner": "distribution/commands/danger-runner.js" } }, + "node_modules/danger/node_modules/@octokit/plugin-paginate-rest": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz", + "integrity": "sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==", + "dev": true, + "dependencies": { + "@octokit/types": "^2.0.1" + } + }, + "node_modules/danger/node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz", + "integrity": "sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==", + "dev": true, + "dependencies": { + "@octokit/types": "^2.0.1", + "deprecation": "^2.3.1" + } + }, + "node_modules/danger/node_modules/@octokit/rest": { + "version": "16.43.2", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.2.tgz", + "integrity": "sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ==", + "dev": true, + "dependencies": { + "@octokit/auth-token": "^2.4.0", + "@octokit/plugin-paginate-rest": "^1.1.1", + "@octokit/plugin-request-log": "^1.0.0", + "@octokit/plugin-rest-endpoint-methods": "2.4.0", + "@octokit/request": "^5.2.0", + "@octokit/request-error": "^1.0.2", + "atob-lite": "^2.0.0", + "before-after-hook": "^2.0.0", + "btoa-lite": "^1.0.0", + "deprecation": "^2.0.0", + "lodash.get": "^4.4.2", + "lodash.set": "^4.3.2", + "lodash.uniq": "^4.5.0", + "octokit-pagination-methods": "^1.1.0", + "once": "^1.4.0", + "universal-user-agent": "^4.0.0" + } + }, + "node_modules/danger/node_modules/@octokit/types": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", + "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", + "dev": true, + "dependencies": { + "@types/node": ">= 8" + } + }, "node_modules/danger/node_modules/micromatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", @@ -6075,6 +6102,26 @@ "node": ">=8.6" } }, + "node_modules/danger/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==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/danger/node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -6090,6 +6137,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/danger/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/danger/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/danger/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -8583,16 +8652,6 @@ "node": ">=10.0" } }, - "node_modules/global-agent/node_modules/core-js": { - "version": "3.16.2", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.16.2.tgz", - "integrity": "sha512-P0KPukO6OjMpjBtHSceAZEWlDD1M2Cpzpg6dBbrjFqFhBHe/BwhxaP820xKOjRn/lZRQirrCusIpLS/n2sgXLQ==", - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/global-agent/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -11963,9 +12022,9 @@ ] }, "node_modules/jsonpointer": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.1.0.tgz", - "integrity": "sha512-CXcRvMyTlnR53xMcKnuMzfCA5i/nfblTnnr74CZb6C4vG39eu6w51t7nKmU5MfLfbTgGItliNyjO/ciNPDqClg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12751,12 +12810,12 @@ } }, "node_modules/memfs-or-file-map-to-github-branch": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/memfs-or-file-map-to-github-branch/-/memfs-or-file-map-to-github-branch-1.2.0.tgz", - "integrity": "sha512-PloI9AkRXrLQuBU1s7eYQpl+4hkL0U0h23lddMaJ3ZGUufn8pdNRxd1kCfBqL5gISCFQs78ttXS15e4/f5vcTA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/memfs-or-file-map-to-github-branch/-/memfs-or-file-map-to-github-branch-1.2.1.tgz", + "integrity": "sha512-I/hQzJ2a/pCGR8fkSQ9l5Yx+FQ4e7X6blNHyWBm2ojeFLT3GVzGkTj7xnyWpdclrr7Nq4dmx3xrvu70m3ypzAQ==", "dev": true, "dependencies": { - "@octokit/rest": "^16.43.1" + "@octokit/rest": "^16.43.0 || ^17.11.0 || ^18.12.0" } }, "node_modules/memorystream": { @@ -14353,10 +14412,9 @@ } }, "node_modules/parse-link-header": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-1.0.1.tgz", - "integrity": "sha1-vt/g0hGK64S+deewJUGeyKYRQKc=", - "dev": true, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-2.0.0.tgz", + "integrity": "sha512-xjU87V0VyHZybn2RrCX5TIFGxTVZE6zqqZWMPlIKiSKuWh/X5WZdt+w1Ki1nXB+8L/KtL+nZ4iq+sfI6MrhhMw==", "dependencies": { "xtend": "~4.0.1" } @@ -19921,37 +19979,6 @@ "typescript": "^4.0.2" } }, - "packages/cli-alert/node_modules/@octokit/plugin-paginate-rest": { - "version": "2.15.1", - "license": "MIT", - "dependencies": { - "@octokit/types": "^6.24.0" - }, - "peerDependencies": { - "@octokit/core": ">=2" - } - }, - "packages/cli-alert/node_modules/@octokit/plugin-rest-endpoint-methods": { - "version": "5.8.0", - "license": "MIT", - "dependencies": { - "@octokit/types": "^6.25.0", - "deprecation": "^2.3.1" - }, - "peerDependencies": { - "@octokit/core": ">=3" - } - }, - "packages/cli-alert/node_modules/@octokit/rest": { - "version": "18.9.1", - "license": "MIT", - "dependencies": { - "@octokit/core": "^3.5.0", - "@octokit/plugin-paginate-rest": "^2.6.2", - "@octokit/plugin-request-log": "^1.0.2", - "@octokit/plugin-rest-endpoint-methods": "5.8.0" - } - }, "packages/cli-alert/node_modules/typescript": { "version": "4.3.5", "license": "Apache-2.0", @@ -20424,6 +20451,14 @@ "requires": { "core-js": "^2.6.5", "regenerator-runtime": "^0.13.4" + }, + "dependencies": { + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "dev": true + } } }, "@babel/template": { @@ -21272,28 +21307,16 @@ } }, "@octokit/openapi-types": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-9.7.0.tgz", - "integrity": "sha512-TUJ16DJU8mekne6+KVcMV5g6g/rJlrnIKn7aALG9QrNpnEipFc1xjoarh0PKaAWf2Hf+HwthRKYt+9mCm5RsRg==" + "version": "12.11.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", + "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==" }, "@octokit/plugin-paginate-rest": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz", - "integrity": "sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==", - "dev": true, + "version": "2.21.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", + "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", "requires": { - "@octokit/types": "^2.0.1" - }, - "dependencies": { - "@octokit/types": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", - "dev": true, - "requires": { - "@types/node": ">= 8" - } - } + "@octokit/types": "^6.40.0" } }, "@octokit/plugin-request-log": { @@ -21303,24 +21326,12 @@ "requires": {} }, "@octokit/plugin-rest-endpoint-methods": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz", - "integrity": "sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==", - "dev": true, + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", + "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", "requires": { - "@octokit/types": "^2.0.1", + "@octokit/types": "^6.39.0", "deprecation": "^2.3.1" - }, - "dependencies": { - "@octokit/types": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", - "dev": true, - "requires": { - "@types/node": ">= 8" - } - } } }, "@octokit/request": { @@ -21376,35 +21387,22 @@ } }, "@octokit/rest": { - "version": "16.43.2", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.2.tgz", - "integrity": "sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ==", - "dev": true, + "version": "18.12.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz", + "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", "requires": { - "@octokit/auth-token": "^2.4.0", - "@octokit/plugin-paginate-rest": "^1.1.1", - "@octokit/plugin-request-log": "^1.0.0", - "@octokit/plugin-rest-endpoint-methods": "2.4.0", - "@octokit/request": "^5.2.0", - "@octokit/request-error": "^1.0.2", - "atob-lite": "^2.0.0", - "before-after-hook": "^2.0.0", - "btoa-lite": "^1.0.0", - "deprecation": "^2.0.0", - "lodash.get": "^4.4.2", - "lodash.set": "^4.3.2", - "lodash.uniq": "^4.5.0", - "octokit-pagination-methods": "^1.1.0", - "once": "^1.4.0", - "universal-user-agent": "^4.0.0" + "@octokit/core": "^3.5.1", + "@octokit/plugin-paginate-rest": "^2.16.8", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^5.12.0" } }, "@octokit/types": { - "version": "6.25.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.25.0.tgz", - "integrity": "sha512-bNvyQKfngvAd/08COlYIN54nRgxskmejgywodizQNyiKoXmWRAjKup2/LYwm+T9V0gsKH6tuld1gM0PzmOiB4Q==", + "version": "6.41.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", + "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", "requires": { - "@octokit/openapi-types": "^9.5.0" + "@octokit/openapi-types": "^12.11.0" } }, "@open-policy-agent/opa-wasm": { @@ -21509,28 +21507,6 @@ "typescript": "^4.0.2" }, "dependencies": { - "@octokit/plugin-paginate-rest": { - "version": "2.15.1", - "requires": { - "@octokit/types": "^6.24.0" - } - }, - "@octokit/plugin-rest-endpoint-methods": { - "version": "5.8.0", - "requires": { - "@octokit/types": "^6.25.0", - "deprecation": "^2.3.1" - } - }, - "@octokit/rest": { - "version": "18.9.1", - "requires": { - "@octokit/core": "^3.5.0", - "@octokit/plugin-paginate-rest": "^2.6.2", - "@octokit/plugin-request-log": "^1.0.2", - "@octokit/plugin-rest-endpoint-methods": "5.8.0" - } - }, "typescript": { "version": "4.3.5" } @@ -21687,16 +21663,6 @@ "needle": "^2.6.0", "parse-link-header": "^2.0.0", "tslib": "^1.10.0" - }, - "dependencies": { - "parse-link-header": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-2.0.0.tgz", - "integrity": "sha512-xjU87V0VyHZybn2RrCX5TIFGxTVZE6zqqZWMPlIKiSKuWh/X5WZdt+w1Ki1nXB+8L/KtL+nZ4iq+sfI6MrhhMw==", - "requires": { - "xtend": "~4.0.1" - } - } } }, "@snyk/fast-glob": { @@ -23493,7 +23459,7 @@ "atob-lite": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz", - "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=", + "integrity": "sha512-LEeSAWeh2Gfa2FtlQE1shxQ8zi5F9GHarrGKz08TMdODD5T4eH6BMsvtnhbWZ+XQn+Gb6om/917ucvRu7l7ukw==", "dev": true }, "aws-sign2": { @@ -23852,7 +23818,7 @@ "btoa-lite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", - "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=", + "integrity": "sha512-gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA==", "dev": true }, "buffer": { @@ -24748,10 +24714,9 @@ } }, "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "dev": true + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.25.0.tgz", + "integrity": "sha512-CVU1xvJEfJGhyCpBrzzzU1kjCfgsGUxhEvwUV2e/cOedYWHdmluamx+knDnmhqALddMG16fZvIqvs9aijsHHaA==" }, "core-util-is": { "version": "1.0.2", @@ -24894,9 +24859,9 @@ } }, "danger": { - "version": "10.7.1", - "resolved": "https://registry.npmjs.org/danger/-/danger-10.7.1.tgz", - "integrity": "sha512-lKyWrWxNxtSfLSsOqse+O9MOrxa++a0kHEBxrgCBvjF36EjNuInuvY06omUTDGdIy6VEbDQRoGeQFIBauj8sMA==", + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/danger/-/danger-10.9.0.tgz", + "integrity": "sha512-eEWQAaIPfWSfzlQiFx+w9fWuP3jwq8VAV9W22EZRxfmCBnkdDa5aN0Akr7lzfCKudzy+4uEmIGUtxnYeFgTthQ==", "dev": true, "requires": { "@babel/polyfill": "^7.2.5", @@ -24912,7 +24877,7 @@ "https-proxy-agent": "^2.2.1", "hyperlinker": "^1.0.0", "json5": "^2.1.0", - "jsonpointer": "^4.0.1", + "jsonpointer": "^5.0.0", "jsonwebtoken": "^8.4.0", "lodash.find": "^4.6.0", "lodash.includes": "^4.3.0", @@ -24923,13 +24888,13 @@ "memfs-or-file-map-to-github-branch": "^1.1.0", "micromatch": "^4.0.4", "node-cleanup": "^2.1.2", - "node-fetch": "2.6.1", + "node-fetch": "^2.6.7", "override-require": "^1.1.1", "p-limit": "^2.1.0", "parse-diff": "^0.7.0", "parse-git-config": "^2.0.3", "parse-github-url": "^1.0.2", - "parse-link-header": "^1.0.1", + "parse-link-header": "^2.0.0", "pinpoint": "^1.1.0", "prettyjson": "^1.2.1", "readline-sync": "^1.4.9", @@ -24937,6 +24902,58 @@ "supports-hyperlinks": "^1.0.1" }, "dependencies": { + "@octokit/plugin-paginate-rest": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz", + "integrity": "sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==", + "dev": true, + "requires": { + "@octokit/types": "^2.0.1" + } + }, + "@octokit/plugin-rest-endpoint-methods": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz", + "integrity": "sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==", + "dev": true, + "requires": { + "@octokit/types": "^2.0.1", + "deprecation": "^2.3.1" + } + }, + "@octokit/rest": { + "version": "16.43.2", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.2.tgz", + "integrity": "sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ==", + "dev": true, + "requires": { + "@octokit/auth-token": "^2.4.0", + "@octokit/plugin-paginate-rest": "^1.1.1", + "@octokit/plugin-request-log": "^1.0.0", + "@octokit/plugin-rest-endpoint-methods": "2.4.0", + "@octokit/request": "^5.2.0", + "@octokit/request-error": "^1.0.2", + "atob-lite": "^2.0.0", + "before-after-hook": "^2.0.0", + "btoa-lite": "^1.0.0", + "deprecation": "^2.0.0", + "lodash.get": "^4.4.2", + "lodash.set": "^4.3.2", + "lodash.uniq": "^4.5.0", + "octokit-pagination-methods": "^1.1.0", + "once": "^1.4.0", + "universal-user-agent": "^4.0.0" + } + }, + "@octokit/types": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", + "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", + "dev": true, + "requires": { + "@types/node": ">= 8" + } + }, "micromatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", @@ -24947,6 +24964,15 @@ "picomatch": "^2.2.3" } }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -24955,6 +24981,28 @@ "requires": { "p-try": "^2.0.0" } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } } } }, @@ -26895,11 +26943,6 @@ "serialize-error": "^7.0.1" }, "dependencies": { - "core-js": { - "version": "3.16.2", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.16.2.tgz", - "integrity": "sha512-P0KPukO6OjMpjBtHSceAZEWlDD1M2Cpzpg6dBbrjFqFhBHe/BwhxaP820xKOjRn/lZRQirrCusIpLS/n2sgXLQ==" - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -29380,9 +29423,9 @@ "dev": true }, "jsonpointer": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.1.0.tgz", - "integrity": "sha512-CXcRvMyTlnR53xMcKnuMzfCA5i/nfblTnnr74CZb6C4vG39eu6w51t7nKmU5MfLfbTgGItliNyjO/ciNPDqClg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", "dev": true }, "JSONStream": { @@ -30045,12 +30088,12 @@ "dev": true }, "memfs-or-file-map-to-github-branch": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/memfs-or-file-map-to-github-branch/-/memfs-or-file-map-to-github-branch-1.2.0.tgz", - "integrity": "sha512-PloI9AkRXrLQuBU1s7eYQpl+4hkL0U0h23lddMaJ3ZGUufn8pdNRxd1kCfBqL5gISCFQs78ttXS15e4/f5vcTA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/memfs-or-file-map-to-github-branch/-/memfs-or-file-map-to-github-branch-1.2.1.tgz", + "integrity": "sha512-I/hQzJ2a/pCGR8fkSQ9l5Yx+FQ4e7X6blNHyWBm2ojeFLT3GVzGkTj7xnyWpdclrr7Nq4dmx3xrvu70m3ypzAQ==", "dev": true, "requires": { - "@octokit/rest": "^16.43.1" + "@octokit/rest": "^16.43.0 || ^17.11.0 || ^18.12.0" } }, "memorystream": { @@ -31288,10 +31331,9 @@ } }, "parse-link-header": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-1.0.1.tgz", - "integrity": "sha1-vt/g0hGK64S+deewJUGeyKYRQKc=", - "dev": true, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-link-header/-/parse-link-header-2.0.0.tgz", + "integrity": "sha512-xjU87V0VyHZybn2RrCX5TIFGxTVZE6zqqZWMPlIKiSKuWh/X5WZdt+w1Ki1nXB+8L/KtL+nZ4iq+sfI6MrhhMw==", "requires": { "xtend": "~4.0.1" } diff --git a/package.json b/package.json index 2edddb4484..6f887fdfdc 100644 --- a/package.json +++ b/package.json @@ -148,7 +148,7 @@ "conventional-changelog-cli": "^2.2.2", "copy-webpack-plugin": "^9.0.1", "cross-spawn": "^6.0.5", - "danger": "10.7.1", + "danger": "10.9.0", "depcheck": "^1.4.3", "eslint": "6.8.0", "eslint-config-prettier": "^6.1.0", From 91ce0291a238cec88d993f2034f30dd33fe58aef Mon Sep 17 00:00:00 2001 From: Yaron Schwimmer Date: Thu, 8 Sep 2022 13:32:28 +0300 Subject: [PATCH 23/55] fix: container python app scan errors --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index af135ec344..8083196b1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,7 +66,7 @@ "semver": "^6.0.0", "snyk-config": "4.0.0", "snyk-cpp-plugin": "2.20.0", - "snyk-docker-plugin": "^5.4.0", + "snyk-docker-plugin": "^5.4.1", "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.22.2", "snyk-module": "3.1.0", @@ -16512,9 +16512,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/snyk-docker-plugin": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.0.tgz", - "integrity": "sha512-9aba6EJqmbJBfYUoYMbqz/ghV2xt02hl8LbFC8OzooXIyu4z72BBRUSfs3geRuLnhSYUIp4etzsOryCuqQdG2g==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.1.tgz", + "integrity": "sha512-x0erNrYCc72ZCj81LL85xibmU763otQACLW8aSUEAsLnSFpoKoE+tnQG5Z9BiEXYbSNXRsll/eS82gzhpHcFKQ==", "dependencies": { "@snyk/composer-lockfile-parser": "^1.4.1", "@snyk/dep-graph": "^2.3.0", @@ -32919,9 +32919,9 @@ } }, "snyk-docker-plugin": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.0.tgz", - "integrity": "sha512-9aba6EJqmbJBfYUoYMbqz/ghV2xt02hl8LbFC8OzooXIyu4z72BBRUSfs3geRuLnhSYUIp4etzsOryCuqQdG2g==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.1.tgz", + "integrity": "sha512-x0erNrYCc72ZCj81LL85xibmU763otQACLW8aSUEAsLnSFpoKoE+tnQG5Z9BiEXYbSNXRsll/eS82gzhpHcFKQ==", "requires": { "@snyk/composer-lockfile-parser": "^1.4.1", "@snyk/dep-graph": "^2.3.0", diff --git a/package.json b/package.json index 2edddb4484..cf7ee04958 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "semver": "^6.0.0", "snyk-config": "4.0.0", "snyk-cpp-plugin": "2.20.0", - "snyk-docker-plugin": "^5.4.0", + "snyk-docker-plugin": "^5.4.1", "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.22.2", "snyk-module": "3.1.0", From e70e43d8a2b5899dbda05882501603bf71186dbf Mon Sep 17 00:00:00 2001 From: Francesco Mari Date: Fri, 9 Sep 2022 13:49:16 +0200 Subject: [PATCH 24/55] feat: pass the org public ID to snyk-iac-test --- src/cli/commands/test/iac/local-execution/types.ts | 1 + src/lib/iac/test/v2/scan/index.ts | 1 + test/jest/unit/cli/commands/test/iac/meta.spec.ts | 1 + test/jest/unit/cli/commands/test/iac/v2/index.spec.ts | 1 + test/jest/unit/iac/index.spec.ts | 1 + test/jest/unit/iac/results-formatter.fixtures.ts | 1 + test/jest/unit/iac/rules/rules.spec.ts | 2 ++ test/jest/unit/lib/iac/test/v2/json.spec.ts | 1 + 8 files changed, 9 insertions(+) diff --git a/src/cli/commands/test/iac/local-execution/types.ts b/src/cli/commands/test/iac/local-execution/types.ts index 2e75318f94..93d5b48687 100644 --- a/src/cli/commands/test/iac/local-execution/types.ts +++ b/src/cli/commands/test/iac/local-execution/types.ts @@ -117,6 +117,7 @@ export interface TestMeta { isPrivate: boolean; isLicensesEnabled: boolean; org: string; + orgPublicId: string; ignoreSettings?: IgnoreSettings | null; projectId?: string; policy?: string; diff --git a/src/lib/iac/test/v2/scan/index.ts b/src/lib/iac/test/v2/scan/index.ts index 9ab3ad66d4..1b641657b4 100644 --- a/src/lib/iac/test/v2/scan/index.ts +++ b/src/lib/iac/test/v2/scan/index.ts @@ -173,6 +173,7 @@ function createTemporaryFiles( const configData = JSON.stringify({ org: options.orgSettings.meta.org, + orgPublicId: options.orgSettings.meta.orgPublicId, apiUrl: config.API, apiAuth: getAuthHeader(), allowAnalytics: allowAnalytics(), diff --git a/test/jest/unit/cli/commands/test/iac/meta.spec.ts b/test/jest/unit/cli/commands/test/iac/meta.spec.ts index 6b12e70e72..994ccc1f8d 100644 --- a/test/jest/unit/cli/commands/test/iac/meta.spec.ts +++ b/test/jest/unit/cli/commands/test/iac/meta.spec.ts @@ -249,6 +249,7 @@ function orgSettingsFor(org) { isPrivate: false, isLicensesEnabled: false, org, + orgPublicId: '7bfa4159-6f90-4acd-82a4-0b2ad2aaf80b', }, }; } diff --git a/test/jest/unit/cli/commands/test/iac/v2/index.spec.ts b/test/jest/unit/cli/commands/test/iac/v2/index.spec.ts index 2f34784c03..77ae812e54 100644 --- a/test/jest/unit/cli/commands/test/iac/v2/index.spec.ts +++ b/test/jest/unit/cli/commands/test/iac/v2/index.spec.ts @@ -49,6 +49,7 @@ describe('test', () => { customPolicies: {}, meta: { org: 'my-org-name', + orgPublicId: '7bfa4159-6f90-4acd-82a4-0b2ad2aaf80b', isLicensesEnabled: false, isPrivate: false, }, diff --git a/test/jest/unit/iac/index.spec.ts b/test/jest/unit/iac/index.spec.ts index 3d641e55ee..7746b5fb8e 100644 --- a/test/jest/unit/iac/index.spec.ts +++ b/test/jest/unit/iac/index.spec.ts @@ -84,6 +84,7 @@ describe('test()', () => { isLicensesEnabled: false, ignoreSettings: null, org: 'org-name', + orgPublicId: '7bfa4159-6f90-4acd-82a4-0b2ad2aaf80b', }, customPolicies: {}, customRules: {}, diff --git a/test/jest/unit/iac/results-formatter.fixtures.ts b/test/jest/unit/iac/results-formatter.fixtures.ts index 5b9796a16b..aca28c0429 100644 --- a/test/jest/unit/iac/results-formatter.fixtures.ts +++ b/test/jest/unit/iac/results-formatter.fixtures.ts @@ -97,6 +97,7 @@ export const meta: TestMeta = { isPrivate: false, isLicensesEnabled: false, org: 'org-name', + orgPublicId: '7bfa4159-6f90-4acd-82a4-0b2ad2aaf80b', }; export function generateCloudConfigResults({ diff --git a/test/jest/unit/iac/rules/rules.spec.ts b/test/jest/unit/iac/rules/rules.spec.ts index 52b428d344..4778499fa9 100644 --- a/test/jest/unit/iac/rules/rules.spec.ts +++ b/test/jest/unit/iac/rules/rules.spec.ts @@ -11,6 +11,7 @@ describe('initRules', () => { isPrivate: false, isLicensesEnabled: false, org: 'my-org', + orgPublicId: '7bfa4159-6f90-4acd-82a4-0b2ad2aaf80b', }, customPolicies: {}, entitlements: { @@ -72,6 +73,7 @@ describe('initRules', () => { isPrivate: false, isLicensesEnabled: false, org: 'my-org', + orgPublicId: '7bfa4159-6f90-4acd-82a4-0b2ad2aaf80b', }, customPolicies: {}, entitlements: { diff --git a/test/jest/unit/lib/iac/test/v2/json.spec.ts b/test/jest/unit/lib/iac/test/v2/json.spec.ts index 359cd29ab1..a74233face 100644 --- a/test/jest/unit/lib/iac/test/v2/json.spec.ts +++ b/test/jest/unit/lib/iac/test/v2/json.spec.ts @@ -58,6 +58,7 @@ describe('convertEngineToJsonResults', () => { isLicensesEnabled: false, ignoreSettings: null, org: 'org-name', + orgPublicId: '7bfa4159-6f90-4acd-82a4-0b2ad2aaf80b', }, customPolicies: {}, customRules: {}, From bb18d47b8007f4be03dfb17a84bcbf6e100ca4df Mon Sep 17 00:00:00 2001 From: Craig Furman Date: Wed, 7 Sep 2022 15:09:17 +0100 Subject: [PATCH 25/55] feat: IaC context-suppressed issue count When snyk-iac-test returns suppressedResults in scan analytics, display a total count of suppressed issues alongside the other scan counts. --- .../formatters/iac-output/text/formatters.ts | 13 + .../iac-output/text/test-summary.ts | 8 + src/lib/formatters/iac-output/text/types.ts | 1 + .../policy-engine/constants/utils.ts | 12 +- src/lib/iac/test/v2/scan/results.ts | 5 + ...yk-iac-test-results-with-suppressions.json | 171 ++++ .../fixtures/snyk-iac-test-results.json | 3 +- ...st-text-output-data-with-suppressions.json | 115 +++ .../fixtures/test-data-with-suppressions.json | 859 ++++++++++++++++++ .../iac-output/text/formatters.spec.ts | 42 + .../iac-output/text/test-summary.spec.ts | 42 +- 11 files changed, 1263 insertions(+), 8 deletions(-) create mode 100644 test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results-with-suppressions.json create mode 100644 test/jest/unit/iac/process-results/fixtures/snyk-iac-test-text-output-data-with-suppressions.json create mode 100644 test/jest/unit/iac/process-results/fixtures/test-data-with-suppressions.json diff --git a/src/lib/formatters/iac-output/text/formatters.ts b/src/lib/formatters/iac-output/text/formatters.ts index f0aa8e9516..698132d9be 100644 --- a/src/lib/formatters/iac-output/text/formatters.ts +++ b/src/lib/formatters/iac-output/text/formatters.ts @@ -109,6 +109,18 @@ export function formatSnykIacTestTestData( ? snykIacTestScanResult.metadata.ignoredCount : 0; + let contextSuppressedIssueCount: number | undefined; + const suppressedResults = + snykIacTestScanResult?.scanAnalytics.suppressedResults; + if (suppressedResults) { + contextSuppressedIssueCount = Object.values(suppressedResults).reduce( + function(count, resourcesForRuleId) { + return (count += resourcesForRuleId.length); + }, + 0, + ); + } + return { resultsBySeverity, metadata: { projectName, orgName }, @@ -118,6 +130,7 @@ export function formatSnykIacTestTestData( filesWithoutIssues: filesWithoutIssuesCount, issues: totalIssues, issuesBySeverity: issuesCountBySeverity, + contextSuppressedIssues: contextSuppressedIssueCount, }, }; } diff --git a/src/lib/formatters/iac-output/text/test-summary.ts b/src/lib/formatters/iac-output/text/test-summary.ts index 11b0fa5179..d17eba9afb 100644 --- a/src/lib/formatters/iac-output/text/test-summary.ts +++ b/src/lib/formatters/iac-output/text/test-summary.ts @@ -62,6 +62,14 @@ function formatCountsSection(testCounts: IacTestCounts): string { `${INDENT}Ignored issues: ${colors.info.bold(`${testCounts.ignores}`)}`, ); + if (testCounts.contextSuppressedIssues) { + countsSectionProperties.push( + `${INDENT}Cloud context - suppressed issues: ${colors.info.bold( + `${testCounts.contextSuppressedIssues}`, + )}`, + ); + } + countsSectionProperties.push( `${INDENT}Total issues: ${colors.info.bold( `${testCounts.issues}`, diff --git a/src/lib/formatters/iac-output/text/types.ts b/src/lib/formatters/iac-output/text/types.ts index 255ff6239b..816f74104c 100644 --- a/src/lib/formatters/iac-output/text/types.ts +++ b/src/lib/formatters/iac-output/text/types.ts @@ -26,6 +26,7 @@ export interface IacTestCounts { filesWithoutIssues: number; issues: number; issuesBySeverity: { [severity in SEVERITY]: number }; + contextSuppressedIssues?: number; } export type IaCTestFailure = { diff --git a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts index a9993e096a..6cc1adeb34 100644 --- a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts +++ b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts @@ -1,11 +1,11 @@ import * as os from 'os'; -const policyEngineChecksums = `11bcf635e209023478f4291fe29e4aa5e4e719dde54dc0e333bae7a626ed6b6d snyk-iac-test_0.29.0_Linux_arm64 -557d4ab7b3c23b34ed81c31109140833dcc4863946774a4ba72d7b18800d4d34 snyk-iac-test_0.29.0_Darwin_x86_64 -7f5db81dad9f7ae4d80c472757b67c37ab29bbb9a18174b30c3354e494fc1505 snyk-iac-test_0.29.0_Linux_x86_64 -89de8e29d0aca232870bd1896aa5c66abb7917566de22d69ff847402b9566690 snyk-iac-test_0.29.0_Darwin_arm64 -cc9d1b48530b69774162e06774fef930e91fb3fe4be8f73e8605a2a6ac7eedfb snyk-iac-test_0.29.0_Windows_x86_64.exe -f1ea52361d5409ad0e2a492425a70c31797d91c999aa510eb7e99f27f575f0a8 snyk-iac-test_0.29.0_Windows_arm64.exe +const policyEngineChecksums = `1ab888458215d8ba45452117854adb95060d9dac45f4b602e2e34f500b7b8a3a snyk-iac-test_0.30.1_Linux_arm64 +85e181989cde63797095107c38772edb4cba75a8becd82aad9c609b4c273789b snyk-iac-test_0.30.1_Windows_arm64.exe +8e4bb3f55d6332706485f278d194f09ef08f46db5516b1008db9c152c636ae24 snyk-iac-test_0.30.1_Windows_x86_64.exe +ba478316de02fd69de4463edca221550d5f4eb962e514220b0a9d9a014d18128 snyk-iac-test_0.30.1_Darwin_arm64 +f218a8e8cc25024f7936947c091e9c9ad34c33178cd6558bdda906fc47c1a598 snyk-iac-test_0.30.1_Darwin_x86_64 +ff23fe190e2392ed4b42ee231171806c300bfe2b9983353497c9f1a195c5c499 snyk-iac-test_0.30.1_Linux_x86_64 `; export const policyEngineVersion = getPolicyEngineVersion(); diff --git a/src/lib/iac/test/v2/scan/results.ts b/src/lib/iac/test/v2/scan/results.ts index 2ac8338af2..0a3cc0045b 100644 --- a/src/lib/iac/test/v2/scan/results.ts +++ b/src/lib/iac/test/v2/scan/results.ts @@ -34,6 +34,7 @@ export interface Results { resources?: Resource[]; vulnerabilities?: Vulnerability[]; metadata: Metadata; + scanAnalytics: ScanAnalytics; } export interface Metadata { @@ -41,6 +42,10 @@ export interface Metadata { ignoredCount: number; } +export interface ScanAnalytics { + suppressedResults?: Record; +} + export interface Vulnerability { rule: Rule; message: string; diff --git a/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results-with-suppressions.json b/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results-with-suppressions.json new file mode 100644 index 0000000000..5ae8c7e5c0 --- /dev/null +++ b/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results-with-suppressions.json @@ -0,0 +1,171 @@ +{ + "results": { + "resources": [ + { + "id": "aws_default_security_group.default", + "type": "aws_default_security_group", + "kind": "terraformconfig", + "file": "plan.json" + }, + { + "id": "aws_vpc.mainvpc", + "type": "aws_vpc", + "kind": "terraformconfig", + "file": "plan.json" + }, + { + "id": "aws_vpc.mainvpc", + "type": "aws_vpc", + "kind": "terraformconfig", + "file": "vpc_group.tf", + "line": 5, + "column": 1 + }, + { + "id": "aws_default_security_group.default", + "type": "aws_default_security_group", + "kind": "terraformconfig", + "file": "vpc_group.tf", + "line": 9, + "column": 1 + } + ], + "vulnerabilities": [ + { + "rule": { + "id": "SNYK-CC-00151", + "title": "VPC flow logging should be enabled", + "description": "VPC flow logging should be enabled. AWS VPC Flow Logs provide visibility into network traffic that traverses the AWS VPC.\nUsers can use the flow logs to detect anomalous traffic or insight during security workflows.\n", + "references": "https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs-cwl.html", + "labels": [ + "logging" + ], + "category": "logging", + "documentation": "https://snyk.io/security-rules/SNYK-CC-00151" + }, + "message": "VPC flow logging should be enabled", + "remediation": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field.", + "severity": "medium", + "ignored": false, + "resource": { + "id": "aws_vpc.mainvpc", + "type": "aws_vpc", + "kind": "terraformconfig", + "formattedPath": "resource.aws_vpc[mainvpc]", + "file": "plan.json" + } + }, + { + "rule": { + "id": "SNYK-CC-TF-5", + "title": "VPC default security group allows unrestricted ingress traffic", + "description": "Configuring all VPC default security groups to restrict all traffic encourages least privilege security\ngroup development and mindful placement of AWS resources into security groups which in turn reduces the exposure of those resources.\n", + "references": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html", + "labels": [ + "best-practices", + "public-access" + ], + "category": "network", + "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-5" + }, + "message": "Inbound traffic to VPC should be more restrictive", + "remediation": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`.\n\nEnsure that an [aws_default_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group) or [aws_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) `ingress` block does NOT contain the value `0.0.0.0/0` in the `cidr_blocks` (`ipv6_cidr_blocks` for ipv6) field.\n\n# Example configuration\n```hcl\nresource \"aws_security_group\" \"example\" {\n ingress {\n cidr_blocks = [10.0.0.0/16]\n from_port = 5900\n to_port = 5900\n # other required fields here\n }\n}\n```\n", + "severity": "medium", + "ignored": false, + "resource": { + "id": "aws_default_security_group.default", + "type": "aws_default_security_group", + "kind": "terraformconfig", + "path": [ + "ingress", + 0, + "cidr_blocks", + 0 + ], + "formattedPath": "input.resource.aws_default_security_group[default].ingress[0].cidr_blocks[0]", + "file": "plan.json" + } + }, + { + "rule": { + "id": "SNYK-CC-00151", + "title": "VPC flow logging should be enabled", + "description": "VPC flow logging should be enabled. AWS VPC Flow Logs provide visibility into network traffic that traverses the AWS VPC.\nUsers can use the flow logs to detect anomalous traffic or insight during security workflows.\n", + "references": "https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs-cwl.html", + "labels": [ + "logging" + ], + "category": "logging", + "documentation": "https://snyk.io/security-rules/SNYK-CC-00151" + }, + "message": "VPC flow logging should be enabled", + "remediation": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field.\n\n# Example Configuration\n\n```hcl\nresource \"aws_vpc\" \"valid_vpc\" {\n# other required fields here\n}\n\nresource \"aws_flow_log\" \"test_flow_log\" {\nvpc_id = \"${aws_vpc.valid_vpc.id}\"\n# other required fields here\n}\n```\n", + "severity": "medium", + "ignored": false, + "resource": { + "id": "aws_vpc.mainvpc", + "type": "aws_vpc", + "kind": "terraformconfig", + "formattedPath": "resource.aws_vpc[mainvpc]", + "file": "vpc_group.tf", + "line": 5, + "column": 1 + } + }, + { + "rule": { + "id": "SNYK-CC-TF-5", + "title": "VPC default security group allows unrestricted ingress traffic", + "description": "Configuring all VPC default security groups to restrict all traffic encourages least privilege security\ngroup development and mindful placement of AWS resources into security groups which in turn reduces the exposure of those resources.\n", + "references": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html", + "labels": [ + "best-practices", + "public-access" + ], + "category": "network", + "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-5" + }, + "message": "Inbound traffic to VPC should be more restrictive", + "remediation": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`.\n\nEnsure that an [aws_default_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group) or [aws_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) `ingress` block does NOT contain the value `0.0.0.0/0` in the `cidr_blocks` (`ipv6_cidr_blocks` for ipv6) field.\n\n# Example configuration\n```hcl\nresource \"aws_security_group\" \"example\" {\n ingress {\n cidr_blocks = [10.0.0.0/16]\n from_port = 5900\n to_port = 5900\n # other required fields here\n }\n}\n```\n", + "severity": "medium", + "ignored": false, + "resource": { + "id": "aws_default_security_group.default", + "type": "aws_default_security_group", + "kind": "terraformconfig", + "path": [ + "ingress", + 0, + "cidr_blocks", + 0 + ], + "formattedPath": "input.resource.aws_default_security_group[default].ingress[0].cidr_blocks[0]", + "file": "vpc_group.tf", + "line": 16, + "column": 5 + } + } + ], + "metadata": { + "projectName": "input-files-for-json-v2", + "ignoredCount": 3 + }, + "scanAnalytics": { + "suppressedResults": { + "issue-1": ["resource1", "resource2"], + "issue-2": ["resource3"] + } + } + }, + "errors": [ + { + "name": "SnykIacTestError", + "code": 2114, + "strCode": "NO_LOADABLE_INPUT", + "userMessage": "The Snyk CLI couldn't find any valid IaC configuration files to scan", + "fields": { + "path": "invalid_file.txt" + } + } + ] +} diff --git a/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results.json b/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results.json index d53e589135..13278ef803 100644 --- a/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results.json +++ b/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results.json @@ -149,7 +149,8 @@ "metadata": { "projectName": "input-files-for-json-v2", "ignoredCount": 3 - } + }, + "scanAnalytics": {} }, "errors": [ { diff --git a/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-text-output-data-with-suppressions.json b/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-text-output-data-with-suppressions.json new file mode 100644 index 0000000000..acc0a54a0e --- /dev/null +++ b/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-text-output-data-with-suppressions.json @@ -0,0 +1,115 @@ +{ + "resultsBySeverity": { + "medium": [ + { + "issue": { + "id": "SNYK-CC-00151", + "severity": "medium", + "title": "VPC flow logging should be enabled", + "lineNumber": -1, + "cloudConfigPath": [ + "aws_vpc", + "mainvpc" + ], + "issue": "VPC flow logging should be enabled", + "impact": "VPC flow logging should be enabled. AWS VPC Flow Logs provide visibility into network traffic that traverses the AWS VPC.\nUsers can use the flow logs to detect anomalous traffic or insight during security workflows.\n", + "resolve": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field.", + "remediation": { + "terraform": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field." + }, + "documentation": "https://snyk.io/security-rules/SNYK-CC-00151" + }, + "targetFile": "plan.json", + "projectType": "terraformconfig" + }, + { + "issue": { + "id": "SNYK-CC-TF-5", + "severity": "medium", + "title": "VPC default security group allows unrestricted ingress traffic", + "lineNumber": -1, + "cloudConfigPath": [ + "aws_default_security_group", + "default", + "ingress", + 0, + "cidr_blocks", + 0 + ], + "issue": "VPC default security group allows unrestricted ingress traffic", + "impact": "Configuring all VPC default security groups to restrict all traffic encourages least privilege security\ngroup development and mindful placement of AWS resources into security groups which in turn reduces the exposure of those resources.\n", + "resolve": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`.", + "remediation": { + "terraform": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`." + }, + "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-5" + }, + "targetFile": "plan.json", + "projectType": "terraformconfig" + }, + { + "issue": { + "id": "SNYK-CC-00151", + "severity": "medium", + "title": "VPC flow logging should be enabled", + "lineNumber": 5, + "cloudConfigPath": [ + "aws_vpc", + "mainvpc" + ], + "issue": "VPC flow logging should be enabled", + "impact": "VPC flow logging should be enabled. AWS VPC Flow Logs provide visibility into network traffic that traverses the AWS VPC.\nUsers can use the flow logs to detect anomalous traffic or insight during security workflows.\n", + "resolve": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field.", + "remediation": { + "terraform": "Reference the `aws_vpc` in an `aws_flog_log` `vpc_id` field." + }, + "documentation": "https://snyk.io/security-rules/SNYK-CC-00151" + }, + "targetFile": "vpc_group.tf", + "projectType": "terraformconfig" + }, + { + "issue": { + "id": "SNYK-CC-TF-5", + "severity": "medium", + "title": "VPC default security group allows unrestricted ingress traffic", + "lineNumber": 16, + "cloudConfigPath": [ + "aws_default_security_group", + "default", + "ingress", + 0, + "cidr_blocks", + 0 + ], + "issue": "VPC default security group allows unrestricted ingress traffic", + "impact": "Configuring all VPC default security groups to restrict all traffic encourages least privilege security\ngroup development and mindful placement of AWS resources into security groups which in turn reduces the exposure of those resources.\n", + "resolve": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`.", + "remediation": { + "terraform": "Remove any invalid `ingress` block from the `aws_security_group` or `aws_default_security_group`." + }, + "documentation": "https://snyk.io/security-rules/SNYK-CC-TF-5" + }, + "targetFile": "vpc_group.tf", + "projectType": "terraformconfig" + } + ] + }, + "metadata": { + "projectName": "project-name", + "orgName": "org-name" + }, + "counts": { + "ignores": 3, + "filesWithIssues": 2, + "filesWithoutIssues": 0, + "issues": 4, + "issuesBySeverity": { + "low": 0, + "medium": 4, + "high": 0, + "critical": 0 + }, + "contextSuppressedIssues": 3 + } +} diff --git a/test/jest/unit/iac/process-results/fixtures/test-data-with-suppressions.json b/test/jest/unit/iac/process-results/fixtures/test-data-with-suppressions.json new file mode 100644 index 0000000000..74012f2772 --- /dev/null +++ b/test/jest/unit/iac/process-results/fixtures/test-data-with-suppressions.json @@ -0,0 +1,859 @@ +{ + "resultsBySeverity": { + "low": [ + { + "issue": { + "severity": "low", + "resolve": "Set `disable_api_termination` attribute with value `true`", + "id": "SNYK-CC-AWS-426", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "msg": "resource.aws_instance[denied].disable_api_termination", + "remediation": { + "cloudformation": "Set `DisableApiTermination` attribute with value `true`", + "terraform": "Set `disable_api_termination` attribute with value `true`" + }, + "subType": "EC2", + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "publicId": "SNYK-CC-AWS-426", + "title": "EC2 API termination protection is not enabled", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination" + ], + "name": "EC2 API termination protection is not enabled", + "cloudConfigPath": [ + "resource", + "aws_instance[denied]", + "disable_api_termination" + ], + "isIgnored": false, + "iacDescription": { + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "resolve": "Set `disable_api_termination` attribute with value `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-426" + }, + "targetFile": "aws_ec2_metadata_secrets.tf", + "projectType": "terraformconfig" + }, + { + "issue": { + "severity": "low", + "resolve": "Set `disable_api_termination` attribute with value `true`", + "id": "SNYK-CC-AWS-426", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "msg": "resource.aws_instance[denied_3].disable_api_termination", + "remediation": { + "cloudformation": "Set `DisableApiTermination` attribute with value `true`", + "terraform": "Set `disable_api_termination` attribute with value `true`" + }, + "subType": "EC2", + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "publicId": "SNYK-CC-AWS-426", + "title": "EC2 API termination protection is not enabled", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination" + ], + "name": "EC2 API termination protection is not enabled", + "cloudConfigPath": [ + "resource", + "aws_instance[denied_3]", + "disable_api_termination" + ], + "isIgnored": false, + "iacDescription": { + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "resolve": "Set `disable_api_termination` attribute with value `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-426" + }, + "targetFile": "aws_ec2_metadata_secrets.tf", + "projectType": "terraformconfig" + }, + { + "issue": { + "severity": "low", + "resolve": "Set `disable_api_termination` attribute with value `true`", + "id": "SNYK-CC-AWS-426", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "msg": "resource.aws_instance[allowed_3].disable_api_termination", + "remediation": { + "cloudformation": "Set `DisableApiTermination` attribute with value `true`", + "terraform": "Set `disable_api_termination` attribute with value `true`" + }, + "subType": "EC2", + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "publicId": "SNYK-CC-AWS-426", + "title": "EC2 API termination protection is not enabled", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination" + ], + "name": "EC2 API termination protection is not enabled", + "cloudConfigPath": [ + "resource", + "aws_instance[allowed_3]", + "disable_api_termination" + ], + "isIgnored": false, + "iacDescription": { + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "resolve": "Set `disable_api_termination` attribute with value `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-426" + }, + "targetFile": "aws_ec2_metadata_secrets.tf", + "projectType": "terraformconfig" + }, + { + "issue": { + "severity": "low", + "resolve": "Set `disable_api_termination` attribute with value `true`", + "id": "SNYK-CC-AWS-426", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "msg": "resource.aws_instance[allowed].disable_api_termination", + "remediation": { + "cloudformation": "Set `DisableApiTermination` attribute with value `true`", + "terraform": "Set `disable_api_termination` attribute with value `true`" + }, + "subType": "EC2", + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "publicId": "SNYK-CC-AWS-426", + "title": "EC2 API termination protection is not enabled", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination" + ], + "name": "EC2 API termination protection is not enabled", + "cloudConfigPath": [ + "resource", + "aws_instance[allowed]", + "disable_api_termination" + ], + "isIgnored": false, + "iacDescription": { + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "resolve": "Set `disable_api_termination` attribute with value `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-426" + }, + "targetFile": "aws_ec2_metadata_secrets.tf", + "projectType": "terraformconfig" + }, + { + "issue": { + "severity": "low", + "resolve": "Set `disable_api_termination` attribute with value `true`", + "id": "SNYK-CC-AWS-426", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "msg": "resource.aws_instance[denied_2].disable_api_termination", + "remediation": { + "cloudformation": "Set `DisableApiTermination` attribute with value `true`", + "terraform": "Set `disable_api_termination` attribute with value `true`" + }, + "subType": "EC2", + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "publicId": "SNYK-CC-AWS-426", + "title": "EC2 API termination protection is not enabled", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination" + ], + "name": "EC2 API termination protection is not enabled", + "cloudConfigPath": [ + "resource", + "aws_instance[denied_2]", + "disable_api_termination" + ], + "isIgnored": false, + "iacDescription": { + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "resolve": "Set `disable_api_termination` attribute with value `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-426" + }, + "targetFile": "aws_ec2_metadata_secrets.tf", + "projectType": "terraformconfig" + }, + { + "issue": { + "severity": "low", + "resolve": "Set `disable_api_termination` attribute with value `true`", + "id": "SNYK-CC-AWS-426", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "msg": "resource.aws_instance[allowed_2].disable_api_termination", + "remediation": { + "cloudformation": "Set `DisableApiTermination` attribute with value `true`", + "terraform": "Set `disable_api_termination` attribute with value `true`" + }, + "subType": "EC2", + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "publicId": "SNYK-CC-AWS-426", + "title": "EC2 API termination protection is not enabled", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination" + ], + "name": "EC2 API termination protection is not enabled", + "cloudConfigPath": [ + "resource", + "aws_instance[allowed_2]", + "disable_api_termination" + ], + "isIgnored": false, + "iacDescription": { + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "resolve": "Set `disable_api_termination` attribute with value `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-426" + }, + "targetFile": "aws_ec2_metadata_secrets.tf", + "projectType": "terraformconfig" + }, + { + "issue": { + "severity": "low", + "resolve": "Set `DisableApiTermination` attribute with value `true`", + "id": "SNYK-CC-AWS-426", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "msg": "Resources[BastionHost].Properties.DisableApiTermination", + "remediation": { + "cloudformation": "Set `DisableApiTermination` attribute with value `true`", + "terraform": "Set `disable_api_termination` attribute with value `true`" + }, + "subType": "EC2", + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "publicId": "SNYK-CC-AWS-426", + "title": "EC2 API termination protection is not enabled", + "references": [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#Using_ChangingDisableAPITermination" + ], + "name": "EC2 API termination protection is not enabled", + "cloudConfigPath": [ + "[DocId: 0]", + "Resources[BastionHost]", + "Properties", + "DisableApiTermination" + ], + "isIgnored": false, + "iacDescription": { + "issue": "To prevent instance from being accidentally terminated using Amazon EC2, you can enable termination protection for the instance", + "impact": "Without this setting enabled the instances can be terminated by accident. This setting should only be used for instances with high availability requirements. Enabling this may prevent IaC workflows from updating the instance, for example terraform will not be able to terminate the instance to update instance type", + "resolve": "Set `DisableApiTermination` attribute with value `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-426" + }, + "targetFile": "bastion.yml", + "projectType": "cloudformationconfig" + }, + { + "issue": { + "severity": "low", + "resolve": "Set `Properties.KmsKeyId` attribute with customer managed key id", + "id": "SNYK-CC-AWS-415", + "impact": "Scope of use of the key cannot be controlled via KMS/IAM policies", + "msg": "Resources[BastionSecureLogGroup].Properties.KmsKeyId", + "remediation": { + "cloudformation": "Set `Properties.KmsKeyId` attribute with customer managed key id", + "terraform": "Set `kms_key_id` attribute with customer managed key id" + }, + "subType": "CloudWatch", + "issue": "Log group is not encrypted with customer managed key", + "publicId": "SNYK-CC-AWS-415", + "title": "CloudWatch log group not encrypted with managed key", + "references": [ + "https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/encrypt-log-data-kms.html", + "https://docs.aws.amazon.com/whitepapers/latest/kms-best-practices/aws-managed-and-customer-managed-cmks.html" + ], + "name": "CloudWatch log group not encrypted with managed key", + "cloudConfigPath": [ + "[DocId: 0]", + "Resources[BastionSecureLogGroup]", + "Properties", + "KmsKeyId" + ], + "isIgnored": false, + "iacDescription": { + "issue": "Log group is not encrypted with customer managed key", + "impact": "Scope of use of the key cannot be controlled via KMS/IAM policies", + "resolve": "Set `Properties.KmsKeyId` attribute with customer managed key id" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-AWS-415" + }, + "targetFile": "bastion.yml", + "projectType": "cloudformationconfig" + }, + { + "issue": { + "severity": "low", + "description": "", + "resolve": "Set `imagePullPolicy` attribute to `Always`", + "id": "SNYK-CC-K8S-42", + "impact": "The container may run with outdated or unauthorized image", + "msg": "spec.template.spec.containers[web].imagePullPolicy", + "subType": "Deployment", + "issue": "The image policy does not prevent image reuse", + "publicId": "SNYK-CC-K8S-42", + "title": "Container could be running with outdated image", + "references": [ + "5.27 Ensure that Docker commands always make use of the latest version of their image", + "https://kubernetes.io/docs/concepts/containers/images/", + "https://kubernetes.io/docs/concepts/configuration/overview/#container-images" + ], + "name": "Container could be running with outdated image", + "cloudConfigPath": [ + "[DocId: 0]", + "spec", + "template", + "spec", + "containers[web]", + "imagePullPolicy" + ], + "isIgnored": false, + "iacDescription": { + "issue": "The image policy does not prevent image reuse", + "impact": "The container may run with outdated or unauthorized image", + "resolve": "Set `imagePullPolicy` attribute to `Always`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-K8S-42" + }, + "targetFile": "k8s.yaml", + "projectType": "k8sconfig" + }, + { + "issue": { + "severity": "low", + "description": "", + "resolve": "Set `securityContext.readOnlyRootFilesystem` to `true`", + "id": "SNYK-CC-K8S-8", + "impact": "Compromised process could abuse writable root filesystem to elevate privileges", + "msg": "input.spec.template.spec.containers[web].securityContext.readOnlyRootFilesystem", + "subType": "Deployment", + "issue": "`readOnlyRootFilesystem` attribute is not set to `true`", + "publicId": "SNYK-CC-K8S-8", + "title": "Container is running with writable root filesystem", + "references": [ + "CIS Docker Benchmark 1.2.0 - Ensure that the container's root filesystem is mounted as read only", + "https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems", + "https://kubernetes.io/blog/2016/08/security-best-practices-kubernetes-deployment/" + ], + "name": "Container is running with writable root filesystem", + "cloudConfigPath": [ + "[DocId: 0]", + "input", + "spec", + "template", + "spec", + "containers[web]", + "securityContext", + "readOnlyRootFilesystem" + ], + "isIgnored": false, + "iacDescription": { + "issue": "`readOnlyRootFilesystem` attribute is not set to `true`", + "impact": "Compromised process could abuse writable root filesystem to elevate privileges", + "resolve": "Set `securityContext.readOnlyRootFilesystem` to `true`" + }, + "lineNumber": -1, + "documentation": "https://snyk.io/security-rules/SNYK-CC-K8S-8" + }, + "targetFile": "k8s.yaml", + "projectType": "k8sconfig" + }, + { + "issue": { + "severity": "low", + "description": "", + "resolve": "Add `container.apparmor.security.beta.kubernetes.io/` annotation with value `runtime/default` or `localhost/` annotation with value `runtime/default` or `localhost/ { 'utf-8', ), ); + const snykIacTestOutputWithSuppressionsFixture: SnykIacTestOutput = JSON.parse( + fs.readFileSync( + path.join( + __dirname, + '..', + '..', + '..', + '..', + 'iac', + 'process-results', + 'fixtures', + 'snyk-iac-test-results-with-suppressions.json', + ), + 'utf-8', + ), + ); const testDataFixture: IacTestData = JSON.parse( fs.readFileSync( @@ -97,6 +113,22 @@ describe('formatSnykIacTestTestData', () => { 'utf-8', ), ); + const testDataWithSuppressionsFixture: IacTestData = JSON.parse( + fs.readFileSync( + path.join( + __dirname, + '..', + '..', + '..', + '..', + 'iac', + 'process-results', + 'fixtures', + 'snyk-iac-test-text-output-data-with-suppressions.json', + ), + 'utf-8', + ), + ); it('formats the test data correctly', () => { const result = formatSnykIacTestTestData( @@ -107,4 +139,14 @@ describe('formatSnykIacTestTestData', () => { expect(result).toEqual(testDataFixture); }); + + it('formats the test data correctly when suppressions are present', () => { + const result = formatSnykIacTestTestData( + snykIacTestOutputWithSuppressionsFixture.results, + 'project-name', + 'org-name', + ); + + expect(result).toEqual(testDataWithSuppressionsFixture); + }); }); diff --git a/test/jest/unit/lib/formatters/iac-output/text/test-summary.spec.ts b/test/jest/unit/lib/formatters/iac-output/text/test-summary.spec.ts index 59bfd9e00a..fab20b555d 100644 --- a/test/jest/unit/lib/formatters/iac-output/text/test-summary.spec.ts +++ b/test/jest/unit/lib/formatters/iac-output/text/test-summary.spec.ts @@ -7,7 +7,7 @@ import { colors } from '../../../../../../../src/lib/formatters/iac-output/text/ import { IacTestData } from '../../../../../../../src/lib/formatters/iac-output/text/types'; describe('formatIacTestSummary', () => { - let testDataFixture: IacTestData; + let testDataFixture, testDataFixtureWithSuppressions: IacTestData; beforeAll(async () => { testDataFixture = JSON.parse( @@ -26,6 +26,22 @@ describe('formatIacTestSummary', () => { 'utf8', ), ); + testDataFixtureWithSuppressions = JSON.parse( + fs.readFileSync( + pathLib.join( + __dirname, + '..', + '..', + '..', + '..', + 'iac', + 'process-results', + 'fixtures', + 'test-data-with-suppressions.json', + ), + 'utf8', + ), + ); }); it("should include the 'Test Summary' title", () => { @@ -65,6 +81,30 @@ describe('formatIacTestSummary', () => { )} ${colors.failure.bold('✗')} Files with issues: ${colors.info.bold('3')} Ignored issues: ${colors.info.bold('3')} + Total issues: ${colors.info.bold('22')} [ ${colors.severities.critical( + '0 critical', + )}, ${colors.severities.high('5 high')}, ${colors.severities.medium( + '4 medium', + )}, ${colors.severities.low('13 low')} ]`, + ); + + expect(result).not.toContain('suppressed issues'); + }); + + it('should include the counts section with the correct values when suppressions are present', () => { + const testTestData: IacTestData = clonedeep( + testDataFixtureWithSuppressions, + ); + + const result = formatIacTestSummary(testTestData); + + expect(result).toContain( + `${colors.success.bold('✔')} Files without issues: ${colors.info.bold( + '0', + )} +${colors.failure.bold('✗')} Files with issues: ${colors.info.bold('3')} + Ignored issues: ${colors.info.bold('3')} + Cloud context - suppressed issues: ${colors.info.bold('42')} Total issues: ${colors.info.bold('22')} [ ${colors.severities.critical( '0 critical', )}, ${colors.severities.high('5 high')}, ${colors.severities.medium( From 7da75f14f5ea71a35bbf58e74c2bfb9eda433179 Mon Sep 17 00:00:00 2001 From: Craig Furman Date: Mon, 12 Sep 2022 16:09:01 +0100 Subject: [PATCH 26/55] feat: can override IaC experimental bundle Using the same environment variable as we do for the regular bundle. This is intended as a developer feature, and is not useful for most users. --- src/lib/iac/test/v2/local-cache/rules-bundle/download.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/iac/test/v2/local-cache/rules-bundle/download.ts b/src/lib/iac/test/v2/local-cache/rules-bundle/download.ts index 106df6f4cd..ba546ca7f9 100644 --- a/src/lib/iac/test/v2/local-cache/rules-bundle/download.ts +++ b/src/lib/iac/test/v2/local-cache/rules-bundle/download.ts @@ -9,12 +9,19 @@ import { saveFile } from '../../../../file-utils'; import { TestConfig } from '../../types'; import { fetchCacheResource } from '../utils'; import { rulesBundleName } from './constants'; +import config from '../../../../../config'; const debugLog = createDebugLogger('snyk-iac'); export async function downloadRulesBundle( testConfig: TestConfig, ): Promise { + // IAC_BUNDLE_PATH is a developer setting that is not useful to most users. It + // is not a replacement for custom rules. + if (config.IAC_BUNDLE_PATH) { + return config.IAC_BUNDLE_PATH; + } + let downloadDurationSeconds = 0; const timer = new TimerMetricInstance('iac_rules_bundle_download'); From da9c1fb0abe4e68e9ed37ce1a57357430fd2c302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Scha=CC=88fer?= <101886095+PeterSchafer@users.noreply.github.com> Date: Tue, 13 Sep 2022 10:25:31 +0200 Subject: [PATCH 27/55] chore: replace local httpauth impl by go-httpauth module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> --- cliv2/cmd/cliv2/main.go | 2 +- cliv2/cmd/cliv2/main_test.go | 2 +- cliv2/go.mod | 22 +- cliv2/go.sum | 49 +- cliv2/internal/httpauth/httpauth.go | 190 ------- .../httpauth/httpauth_generated_mock.go | 140 ----- cliv2/internal/httpauth/httpauth_test.go | 232 -------- .../internal/httpauth/proxy_authenticator.go | 294 ---------- .../httpauth/proxy_authenticator_test.go | 513 ------------------ cliv2/internal/httpauth/spnego.go | 61 --- .../httpauth/spnego_generated_mock.go | 78 --- cliv2/internal/httpauth/spnego_nonwindows.go | 121 ----- cliv2/internal/httpauth/spnego_test.go | 169 ------ cliv2/internal/httpauth/spnego_windows.go | 76 --- .../httpauth/test/helper/mock_http_server.go | 54 -- cliv2/internal/proxy/proxy.go | 2 +- cliv2/internal/proxy/proxy_test.go | 2 +- .../acceptance/proxy_authentication.spec.ts | 9 +- .../fixtures/squid_environment/Dockerfile | 0 .../squid_environment/docker-compose.yml | 0 .../squid_environment/scripts/setup.sh | 0 21 files changed, 51 insertions(+), 1965 deletions(-) delete mode 100644 cliv2/internal/httpauth/httpauth.go delete mode 100644 cliv2/internal/httpauth/httpauth_generated_mock.go delete mode 100644 cliv2/internal/httpauth/httpauth_test.go delete mode 100644 cliv2/internal/httpauth/proxy_authenticator.go delete mode 100644 cliv2/internal/httpauth/proxy_authenticator_test.go delete mode 100644 cliv2/internal/httpauth/spnego.go delete mode 100644 cliv2/internal/httpauth/spnego_generated_mock.go delete mode 100644 cliv2/internal/httpauth/spnego_nonwindows.go delete mode 100644 cliv2/internal/httpauth/spnego_test.go delete mode 100644 cliv2/internal/httpauth/spnego_windows.go delete mode 100644 cliv2/internal/httpauth/test/helper/mock_http_server.go rename cliv2/{internal/httpauth => }/test/fixtures/squid_environment/Dockerfile (100%) rename cliv2/{internal/httpauth => }/test/fixtures/squid_environment/docker-compose.yml (100%) rename cliv2/{internal/httpauth => }/test/fixtures/squid_environment/scripts/setup.sh (100%) diff --git a/cliv2/cmd/cliv2/main.go b/cliv2/cmd/cliv2/main.go index 9e81264bd7..a4bc909723 100644 --- a/cliv2/cmd/cliv2/main.go +++ b/cliv2/cmd/cliv2/main.go @@ -7,9 +7,9 @@ import ( "os" "github.com/snyk/cli/cliv2/internal/cliv2" - "github.com/snyk/cli/cliv2/internal/httpauth" "github.com/snyk/cli/cliv2/internal/proxy" "github.com/snyk/cli/cliv2/internal/utils" + "github.com/snyk/go-httpauth/pkg/httpauth" ) type EnvironmentVariables struct { diff --git a/cliv2/cmd/cliv2/main_test.go b/cliv2/cmd/cliv2/main_test.go index 4360cad65d..0b1ffa1f89 100644 --- a/cliv2/cmd/cliv2/main_test.go +++ b/cliv2/cmd/cliv2/main_test.go @@ -6,7 +6,7 @@ import ( "testing" main "github.com/snyk/cli/cliv2/cmd/cliv2" - "github.com/snyk/cli/cliv2/internal/httpauth" + "github.com/snyk/go-httpauth/pkg/httpauth" "github.com/stretchr/testify/assert" ) diff --git a/cliv2/go.mod b/cliv2/go.mod index 2f60c0cd1e..6b22e3414f 100644 --- a/cliv2/go.mod +++ b/cliv2/go.mod @@ -3,24 +3,26 @@ module github.com/snyk/cli/cliv2 go 1.18 require ( - github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 github.com/elazarl/goproxy v0.0.0-20220328115640-894aeddb713e - github.com/golang/mock v1.6.0 - github.com/jcmturner/gokrb5/v8 v8.4.2 - github.com/stretchr/testify v1.7.0 - golang.org/x/net v0.0.0-20220630215102-69896b714898 + github.com/snyk/go-httpauth v0.0.0-20220912133144-d51219ca664d + github.com/stretchr/testify v1.8.0 ) require ( - github.com/davecgh/go-spew v1.1.0 // indirect - github.com/hashicorp/go-uuid v1.0.2 // indirect + github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/golang/mock v1.6.0 // indirect + github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect - github.com/jcmturner/gofork v1.0.0 // indirect + github.com/jcmturner/gofork v1.7.6 // indirect github.com/jcmturner/goidentity/v6 v6.0.1 // indirect + github.com/jcmturner/gokrb5/v8 v8.4.3 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/kr/text v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 // indirect + golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 // indirect + golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c // indirect golang.org/x/text v0.3.7 // indirect - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/cliv2/go.sum b/cliv2/go.sum index f5d4e59039..5bf1a0265e 100644 --- a/cliv2/go.sum +++ b/cliv2/go.sum @@ -1,7 +1,9 @@ github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/elazarl/goproxy v0.0.0-20220328115640-894aeddb713e h1:99KFda6F/mw8xSfceY2JEVCrYWX7l+Ms6BcO5wEct+Q= github.com/elazarl/goproxy v0.0.0-20220328115640-894aeddb713e/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM= @@ -12,50 +14,66 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= -github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= -github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= +github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= -github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA= -github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= +github.com/jcmturner/gokrb5/v8 v8.4.3 h1:iTonLeSJOn7MVUtyMT+arAn5AKAPrkilzhGw8wE/Tq8= +github.com/jcmturner/gokrb5/v8 v8.4.3/go.mod h1:dqRwJGXznQrzw6cWmyo6kH+E7jksEQG/CyVWsJEsJO0= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/snyk/go-httpauth v0.0.0-20220912133144-d51219ca664d h1:dT2rfoDxGDWeplsnXWajWZcZ7zo8R6Hif3jufvkXcUE= +github.com/snyk/go-httpauth v0.0.0-20220912133144-d51219ca664d/go.mod h1:v6t6wKizOcHXT3p4qKn6Bda7yNIjCQ54Xyl31NjgXkY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9 h1:umElSU9WZirRdgu2yFHY0ayQkEnKiOC1TtM3fWXFnoU= -golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 h1:GIAS/yBem/gq2MUqgNIzUHW7cJMmx3TGZOrnyYaNQ6c= +golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20220630215102-69896b714898 h1:K7wO6V1IrczY9QOQ2WkVpw4JQSwCd52UsxVEirZUfiw= -golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= +golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c h1:JVAXQ10yGGVbSyoer5VILysz6YKjdNT2bsvlayjqhes= +golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -64,8 +82,9 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/cliv2/internal/httpauth/httpauth.go b/cliv2/internal/httpauth/httpauth.go deleted file mode 100644 index 42c67ffd12..0000000000 --- a/cliv2/internal/httpauth/httpauth.go +++ /dev/null @@ -1,190 +0,0 @@ -package httpauth - -import ( - "fmt" - "io" - "log" - "net/url" - "strings" -) - -type AuthenticationMechanism string -type AuthenticationState int - -const maxCycleCount int = 10 - -const ( - NoAuth AuthenticationMechanism = "noauth" - Negotiate AuthenticationMechanism = "negotiate" - AnyAuth AuthenticationMechanism = "anyauth" - UnknownMechanism AuthenticationMechanism = "unknownmechanism" -) - -const ( - Initial AuthenticationState = iota - Negotiating AuthenticationState = iota - Done AuthenticationState = iota - Error AuthenticationState = iota - Cancel AuthenticationState = iota - Close AuthenticationState = iota -) - -const ( - AuthorizationKey string = "Authorization" - ProxyAuthorizationKey string = "Proxy-Authorization" - ProxyAuthenticateKey string = "Proxy-Authenticate" -) - -type AuthenticationHandlerInterface interface { - Close() - Cancel() - Succesful() - IsStopped() bool - GetAuthorizationValue(url *url.URL, responseToken string) (string, error) - Update(availableMechanism map[AuthenticationMechanism]string) (string, error) - SetLogger(logger *log.Logger) - SetSpnegoProvider(spnegoProvider SpnegoProvider) -} - -type AuthenticationHandler struct { - spnegoProvider SpnegoProvider - Mechanism AuthenticationMechanism - activeMechanism AuthenticationMechanism - state AuthenticationState - cycleCount int - logger *log.Logger -} - -func NewHandler(mechanism AuthenticationMechanism) AuthenticationHandlerInterface { - a := &AuthenticationHandler{ - spnegoProvider: SpnegoProviderInstance(), - Mechanism: mechanism, - activeMechanism: mechanism, - state: Initial, - logger: log.New(io.Discard, "", 0), - } - - return a -} - -func (a *AuthenticationHandler) Close() { - a.spnegoProvider.Close() - a.state = Close -} - -func (a *AuthenticationHandler) GetAuthorizationValue(url *url.URL, responseToken string) (authorizeValue string, err error) { - mechanism := StringFromAuthenticationMechanism(a.activeMechanism) - - if a.activeMechanism == Negotiate { // supporting mechanism: Negotiate (SPNEGO) - var token string - var done bool - - if len(responseToken) == 0 && Negotiating == a.state { - a.state = Error - return "", fmt.Errorf("Authentication failed! Unexpected empty token during negotiation!") - } - - a.state = Negotiating - - token, done, err = a.spnegoProvider.GetToken(url, responseToken) - if err != nil { - a.state = Error - return "", err - } - - if done { - a.logger.Println("Local security context established!") - } - - authorizeValue = mechanism + " " + token - - if len(token) > 0 { - mechanisms, _ := GetMechanismsFromHttpFieldValue(authorizeValue) - a.logger.Printf("Authorization to %s using: %s", url, mechanisms) - } - } - - a.cycleCount++ - if a.cycleCount >= maxCycleCount { - err = fmt.Errorf("Failed to authenticate within %d cycles, stopping now!", maxCycleCount) - authorizeValue = "" - } - - return authorizeValue, err -} - -func (a *AuthenticationHandler) Update(availableMechanism map[AuthenticationMechanism]string) (responseToken string, err error) { - - // if AnyAuth is selected, we need to determine the best supported mechanism on both sides - if a.activeMechanism == AnyAuth { - // currently we only support Negotiate, AnyAuth will use Negotiate if the communication partner proposes it - if _, ok := availableMechanism[Negotiate]; ok { - a.activeMechanism = Negotiate - a.logger.Printf("Selected Mechanism: %s\n", StringFromAuthenticationMechanism(a.activeMechanism)) - } - } - - // extract the token for the active mechanism - if token, ok := availableMechanism[a.activeMechanism]; ok { - responseToken = token - } else { - err = fmt.Errorf("Incorrect or unsupported Mechanism detected! %s", availableMechanism) - } - - return responseToken, err -} - -func (a *AuthenticationHandler) IsStopped() bool { - return (a.state == Done || a.state == Error || a.state == Cancel || a.state == Close) -} - -func (a *AuthenticationHandler) Cancel() { - a.state = Cancel - a.logger.Println("AuthenticationHandler.Cancel()") -} - -func (a *AuthenticationHandler) Succesful() { - a.state = Done - a.logger.Println("AuthenticationHandler.Succesful()") -} - -func (a *AuthenticationHandler) SetLogger(logger *log.Logger) { - a.logger = logger - a.spnegoProvider.SetLogger(logger) -} - -func (a *AuthenticationHandler) SetSpnegoProvider(spnegoProvider SpnegoProvider) { - a.spnegoProvider = spnegoProvider -} - -func StringFromAuthenticationMechanism(mechanism AuthenticationMechanism) string { - return strings.Title(string(mechanism)) -} - -func AuthenticationMechanismFromString(mechanism string) AuthenticationMechanism { - tmp := strings.ToLower(mechanism) - return AuthenticationMechanism(tmp) -} - -func GetMechanismAndToken(HttpFieldValue string) (AuthenticationMechanism, string) { - mechanism := UnknownMechanism - token := "" - - authenticateValue := strings.Split(HttpFieldValue, " ") - if len(authenticateValue) >= 1 { - mechanism = AuthenticationMechanismFromString(authenticateValue[0]) - } - - if len(authenticateValue) == 2 { - token = authenticateValue[1] - } - - return mechanism, token -} - -func IsSupportedMechanism(mechanism AuthenticationMechanism) bool { - if mechanism == Negotiate || mechanism == AnyAuth { - return true - } - return false -} diff --git a/cliv2/internal/httpauth/httpauth_generated_mock.go b/cliv2/internal/httpauth/httpauth_generated_mock.go deleted file mode 100644 index e814a43396..0000000000 --- a/cliv2/internal/httpauth/httpauth_generated_mock.go +++ /dev/null @@ -1,140 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: httpauth.go - -// Package httpauth is a generated GoMock package. -package httpauth - -import ( - log "log" - url "net/url" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" -) - -// MockAuthenticationHandlerInterface is a mock of AuthenticationHandlerInterface interface. -type MockAuthenticationHandlerInterface struct { - ctrl *gomock.Controller - recorder *MockAuthenticationHandlerInterfaceMockRecorder -} - -// MockAuthenticationHandlerInterfaceMockRecorder is the mock recorder for MockAuthenticationHandlerInterface. -type MockAuthenticationHandlerInterfaceMockRecorder struct { - mock *MockAuthenticationHandlerInterface -} - -// NewMockAuthenticationHandlerInterface creates a new mock instance. -func NewMockAuthenticationHandlerInterface(ctrl *gomock.Controller) *MockAuthenticationHandlerInterface { - mock := &MockAuthenticationHandlerInterface{ctrl: ctrl} - mock.recorder = &MockAuthenticationHandlerInterfaceMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockAuthenticationHandlerInterface) EXPECT() *MockAuthenticationHandlerInterfaceMockRecorder { - return m.recorder -} - -// Cancel mocks base method. -func (m *MockAuthenticationHandlerInterface) Cancel() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Cancel") -} - -// Cancel indicates an expected call of Cancel. -func (mr *MockAuthenticationHandlerInterfaceMockRecorder) Cancel() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Cancel", reflect.TypeOf((*MockAuthenticationHandlerInterface)(nil).Cancel)) -} - -// Close mocks base method. -func (m *MockAuthenticationHandlerInterface) Close() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Close") -} - -// Close indicates an expected call of Close. -func (mr *MockAuthenticationHandlerInterfaceMockRecorder) Close() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockAuthenticationHandlerInterface)(nil).Close)) -} - -// GetAuthorizationValue mocks base method. -func (m *MockAuthenticationHandlerInterface) GetAuthorizationValue(url *url.URL, responseToken string) (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAuthorizationValue", url, responseToken) - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetAuthorizationValue indicates an expected call of GetAuthorizationValue. -func (mr *MockAuthenticationHandlerInterfaceMockRecorder) GetAuthorizationValue(url, responseToken interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorizationValue", reflect.TypeOf((*MockAuthenticationHandlerInterface)(nil).GetAuthorizationValue), url, responseToken) -} - -// IsStopped mocks base method. -func (m *MockAuthenticationHandlerInterface) IsStopped() bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsStopped") - ret0, _ := ret[0].(bool) - return ret0 -} - -// IsStopped indicates an expected call of IsStopped. -func (mr *MockAuthenticationHandlerInterfaceMockRecorder) IsStopped() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsStopped", reflect.TypeOf((*MockAuthenticationHandlerInterface)(nil).IsStopped)) -} - -// SetLogger mocks base method. -func (m *MockAuthenticationHandlerInterface) SetLogger(logger *log.Logger) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetLogger", logger) -} - -// SetLogger indicates an expected call of SetLogger. -func (mr *MockAuthenticationHandlerInterfaceMockRecorder) SetLogger(logger interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLogger", reflect.TypeOf((*MockAuthenticationHandlerInterface)(nil).SetLogger), logger) -} - -// SetSpnegoProvider mocks base method. -func (m *MockAuthenticationHandlerInterface) SetSpnegoProvider(spnegoProvider SpnegoProvider) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSpnegoProvider", spnegoProvider) -} - -// SetSpnegoProvider indicates an expected call of SetSpnegoProvider. -func (mr *MockAuthenticationHandlerInterfaceMockRecorder) SetSpnegoProvider(spnegoProvider interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSpnegoProvider", reflect.TypeOf((*MockAuthenticationHandlerInterface)(nil).SetSpnegoProvider), spnegoProvider) -} - -// Succesful mocks base method. -func (m *MockAuthenticationHandlerInterface) Succesful() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Succesful") -} - -// Succesful indicates an expected call of Succesful. -func (mr *MockAuthenticationHandlerInterfaceMockRecorder) Succesful() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Succesful", reflect.TypeOf((*MockAuthenticationHandlerInterface)(nil).Succesful)) -} - -// Update mocks base method. -func (m *MockAuthenticationHandlerInterface) Update(availableMechanism map[AuthenticationMechanism]string) (string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Update", availableMechanism) - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Update indicates an expected call of Update. -func (mr *MockAuthenticationHandlerInterfaceMockRecorder) Update(availableMechanism interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockAuthenticationHandlerInterface)(nil).Update), availableMechanism) -} diff --git a/cliv2/internal/httpauth/httpauth_test.go b/cliv2/internal/httpauth/httpauth_test.go deleted file mode 100644 index f036b110ae..0000000000 --- a/cliv2/internal/httpauth/httpauth_test.go +++ /dev/null @@ -1,232 +0,0 @@ -package httpauth - -import ( - "fmt" - "log" - "net/url" - "os" - "testing" - - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/assert" -) - -var testLogger = log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lmicroseconds|log.Lshortfile) - -const ( - NTML_01_INITIALMESSAGE = "TlRMTVNTUAABAAAAl4II4gAAAAAAAAAAAAAAAAAAAAAKADk4AAAADw==" - NTML_02_CHALLENGE = "TlRMTVNTUAACAAAADgAOADgAAAAVgoni63VPOgRoQ04AAAAAAAAAAKQApABGAAAABgEAAAAAAA9IAEEATQBNAEUAUgAyAAIADgBIAEEATQBNAEUAUgAyAAEAHABFAEMAMgBBAE0AQQBaAC0AVgBVAEgATABOAFEABAAeAGgAYQBtAG0AZQByADIALgBzAG4AeQBrAC4AaQBvAAMAPABlAGMAMgBhAG0AYQB6AC0AdgB1AGgAbABuAHEALgBoAGEAbQBtAGUAcgAyAC4AcwBuAHkAawAuAGkAbwAHAAgAzu0E3y2j2AEAAAAA" - NTML_03_RESPONSE = "TlRMTVNTUAADAAAAGAAYAI4AAABcAVwBpgAAAA4ADgBYAAAACgAKAGYAAAAeAB4AcAAAABAAEAACAgAAFYKI4goAOTgAAAAPxbettwPT/UuVcj7f+eHILmgAYQBtAG0AZQByADIAQQBkAG0AaQBuAEUAQwAyAEEATQBBAFoALQA4ADMATwBVADMARABUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/6ZPp6zbTJBkvgadfD80wBAQAAAAAAAM7tBN8to9gBZ6ejc1nCVp0AAAAAAgAOAEgAQQBNAE0ARQBSADIAAQAcAEUAQwAyAEEATQBBAFoALQBWAFUASABMAE4AUQAEAB4AaABhAG0AbQBlAHIAMgAuAHMAbgB5AGsALgBpAG8AAwA8AGUAYwAyAGEAbQBhAHoALQB2AHUAaABsAG4AcQAuAGgAYQBtAG0AZQByADIALgBzAG4AeQBrAC4AaQBvAAcACADO7QTfLaPYAQYABAACAAAACAAwADAAAAAAAAAAAQAAAAAgAADQl5cStKyz5f8Kuwh+f2BiiWY4vHopxNdJTsXVQqRoLgoAEAAAAAAAAAAAAAAAAAAAAAAACQA0AEgAVABUAFAALwBwAHIAbwB4AHkALgBoAGEAbQBtAGUAcgAyAC4AcwBuAHkAawAuAGkAbwAAAAAAAAAAACKmvM2kkvW9vroG6NaLu8s=" -) - -func Test_DisableAuthentication(t *testing.T) { - - proxyAddr, _ := url.Parse("http://127.0.0.1") - expectedValue := "" - - authHandler := NewHandler(NoAuth) - - actualValue, err := authHandler.GetAuthorizationValue(proxyAddr, "") - assert.Nil(t, err) - - assert.Equal(t, expectedValue, actualValue) - -} - -func Test_EnabledAuthentication_Negotiate_Success_NLTM(t *testing.T) { - - // specify test data - proxyAddr, _ := url.Parse("http://127.0.0.1") - mechanism := Negotiate - expectedValue := StringFromAuthenticationMechanism(mechanism) - - // setup test environment - spnegoProviderMock := NewMockSpnegoProvider(gomock.NewController(t)) - defer spnegoProviderMock.ctrl.Finish() - spnegoProviderMock.EXPECT().GetToken(proxyAddr, "").Times(1).Return(NTML_01_INITIALMESSAGE, false, nil) - spnegoProviderMock.EXPECT().GetToken(proxyAddr, NTML_02_CHALLENGE).Times(1).Return(NTML_03_RESPONSE, true, nil) - - authHandler := NewHandler(mechanism) - authHandler.SetSpnegoProvider(spnegoProviderMock) - - // actually test - actualValue, err := authHandler.GetAuthorizationValue(proxyAddr, "") - assert.Nil(t, err) - assert.Contains(t, actualValue, expectedValue) - assert.False(t, authHandler.IsStopped()) - - actualValue, err = authHandler.GetAuthorizationValue(proxyAddr, NTML_02_CHALLENGE) - assert.Nil(t, err) - assert.Contains(t, actualValue, expectedValue) - assert.False(t, authHandler.IsStopped()) - - authHandler.Succesful() - assert.True(t, authHandler.IsStopped()) -} - -func Test_EnabledAuthentication_Negotiate_Fail_NLTM01(t *testing.T) { - - // specify test data - proxyAddr, _ := url.Parse("http://127.0.0.1") - mechanism := Negotiate - expectedValue := StringFromAuthenticationMechanism(mechanism) - - // setup test environment - spnegoProviderMock := NewMockSpnegoProvider(gomock.NewController(t)) - defer spnegoProviderMock.ctrl.Finish() - spnegoProviderMock.EXPECT().GetToken(proxyAddr, "").Times(1).Return(NTML_01_INITIALMESSAGE, false, nil) - - authHandler := NewHandler(mechanism) - authHandler.SetSpnegoProvider(spnegoProviderMock) - - // actually test - actualValue, err := authHandler.GetAuthorizationValue(proxyAddr, "") - assert.Nil(t, err) - assert.Contains(t, actualValue, expectedValue) - assert.False(t, authHandler.IsStopped()) - - actualValue, err = authHandler.GetAuthorizationValue(proxyAddr, "") // unexpected during negotiation - assert.NotNil(t, err) - assert.Empty(t, actualValue) - assert.True(t, authHandler.IsStopped()) -} - -func Test_EnabledAuthentication_Negotiate_Fail_NLTM02(t *testing.T) { - - // specify test data - proxyAddr, _ := url.Parse("http://127.0.0.1") - mechanism := Negotiate - expectedValue := StringFromAuthenticationMechanism(mechanism) - incorrectResponseToken := "Some incorrect token maybe" - - // setup test environment - spnegoProviderMock := NewMockSpnegoProvider(gomock.NewController(t)) - defer spnegoProviderMock.ctrl.Finish() - spnegoProviderMock.EXPECT().GetToken(proxyAddr, "").Times(1).Return(NTML_01_INITIALMESSAGE, false, nil) - spnegoProviderMock.EXPECT().GetToken(proxyAddr, incorrectResponseToken).Times(1).Return("", false, fmt.Errorf("Something went wrong")) // returning an error from the spnegoProvider - - authHandler := NewHandler(mechanism) - authHandler.SetSpnegoProvider(spnegoProviderMock) - - // actually test - actualValue, err := authHandler.GetAuthorizationValue(proxyAddr, "") - assert.Nil(t, err) - assert.Contains(t, actualValue, expectedValue) - assert.False(t, authHandler.IsStopped()) - - actualValue, err = authHandler.GetAuthorizationValue(proxyAddr, incorrectResponseToken) - assert.NotNil(t, err) - assert.Empty(t, actualValue) - assert.True(t, authHandler.IsStopped()) -} - -func Test_EnabledAuthentication_Negotiate_Fail_NLTM03(t *testing.T) { - - // specify test data - proxyAddr, _ := url.Parse("http://127.0.0.1") - mechanism := Negotiate - expectedValue := StringFromAuthenticationMechanism(mechanism) - - // setup test environment - spnegoProviderMock := NewMockSpnegoProvider(gomock.NewController(t)) - defer spnegoProviderMock.ctrl.Finish() - spnegoProviderMock.EXPECT().GetToken(proxyAddr, "").Times(1).Return(NTML_01_INITIALMESSAGE, false, nil) - spnegoProviderMock.EXPECT().GetToken(proxyAddr, NTML_02_CHALLENGE).MinTimes(2).Return("", false, nil) - - authHandler := NewHandler(mechanism) - authHandler.SetSpnegoProvider(spnegoProviderMock) - - // actually test - actualValue, err := authHandler.GetAuthorizationValue(proxyAddr, "") - assert.Nil(t, err) - assert.Contains(t, actualValue, expectedValue) - assert.False(t, authHandler.IsStopped()) - - for i := 0; i < maxCycleCount-2; i++ { - actualValue, err = authHandler.GetAuthorizationValue(proxyAddr, NTML_02_CHALLENGE) - assert.Nil(t, err) - assert.Contains(t, actualValue, expectedValue) - assert.False(t, authHandler.IsStopped()) - } - - actualValue, err = authHandler.GetAuthorizationValue(proxyAddr, NTML_02_CHALLENGE) // exceed max cycles of authentication messages exchanged - assert.NotNil(t, err) - assert.Empty(t, actualValue) - assert.False(t, authHandler.IsStopped()) - -} - -func Test_EnabledAuthentication_Negotiate_Update_AnyAuth_success(t *testing.T) { - // specify test data - mechanism := AnyAuth - expectedToken := "ghi" - availableMechanism := map[AuthenticationMechanism]string{ - NoAuth: "abc", - Negotiate: expectedToken, - UnknownMechanism: "def", - } - - // setup test environment - authHandler := NewHandler(mechanism) - - actualToken, err := authHandler.Update(availableMechanism) - assert.Nil(t, err) - assert.Equal(t, expectedToken, actualToken) -} - -func Test_EnabledAuthentication_Negotiate_Update_AnyAuth_fail(t *testing.T) { - // specify test data - mechanism := AnyAuth - expectedToken := "" - availableMechanism := map[AuthenticationMechanism]string{ - NoAuth: "abc", - UnknownMechanism: "def", - } - - // setup test environment - authHandler := NewHandler(mechanism) - - actualToken, err := authHandler.Update(availableMechanism) - assert.NotNil(t, err) - assert.Equal(t, expectedToken, actualToken) -} - -func Test_AuthenticationMechanismFromAndToString(t *testing.T) { - - testSet := []AuthenticationMechanism{ - AnyAuth, - Negotiate, - NoAuth, - UnknownMechanism, - } - - var mechanismConverted AuthenticationMechanism - var mechanismString string - - for _, mechanism := range testSet { - mechanismString = StringFromAuthenticationMechanism(mechanism) - mechanismConverted = AuthenticationMechanismFromString(mechanismString) - assert.Equal(t, mechanism, mechanismConverted) - } - - // different casing - mechanismConverted = AuthenticationMechanismFromString("NEGOTIATE") - assert.Equal(t, Negotiate, mechanismConverted) -} - -func Test_LookupSchemeFromAddress(t *testing.T) { - defaultValue := "none" - - input := map[string]string{ - "snyk.io:443": "https", - "snyk.io:80": "http", - "snyk.io:1080": "socks5", - "snyk.io": defaultValue, - "snyk.io:443:das": defaultValue, - } - - for addr, expected := range input { - actual := LookupSchemeFromCannonicalAddress(addr, defaultValue) - assert.Equal(t, expected, actual) - } -} diff --git a/cliv2/internal/httpauth/proxy_authenticator.go b/cliv2/internal/httpauth/proxy_authenticator.go deleted file mode 100644 index 0a759ad16e..0000000000 --- a/cliv2/internal/httpauth/proxy_authenticator.go +++ /dev/null @@ -1,294 +0,0 @@ -package httpauth - -import ( - "bufio" - "context" - "fmt" - "log" - "net" - "net/http" - "net/url" - "strings" - "time" - - "golang.org/x/net/idna" -) - -type ProxyAuthenticator struct { - acceptedProxyAuthMechanism AuthenticationMechanism - debugLogger *log.Logger - upstreamProxy func(*http.Request) (*url.URL, error) - CreateHandler func(mechanism AuthenticationMechanism) AuthenticationHandlerInterface -} - -func NewProxyAuthenticator(mechanism AuthenticationMechanism, upstreamProxy func(*http.Request) (*url.URL, error), logger *log.Logger) *ProxyAuthenticator { - authenticator := &ProxyAuthenticator{ - acceptedProxyAuthMechanism: mechanism, - debugLogger: logger, - upstreamProxy: upstreamProxy, - CreateHandler: NewHandler, - } - return authenticator -} - -// This is the main entry point function for the ProxyAuthenticator when being used with http.Transport. -// It should be used like this: transport.DialContext = DialContext -// It'll be invoked by http.Transport when it requires a new TCP connection. -func (p *ProxyAuthenticator) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { - var connection net.Conn - var err error - var proxyUrl *url.URL - - if p.upstreamProxy != nil { - fakeRequest := &http.Request{URL: &url.URL{}} - fakeRequest.URL.Scheme = LookupSchemeFromCannonicalAddress(addr, "https") - fakeRequest.URL.Host = addr - proxyUrl, err = p.upstreamProxy(fakeRequest) - if err != nil { - return nil, err - } - } - - if proxyUrl != nil { - proxyAddr := CanonicalAddr(proxyUrl) - createConnectionFunc := func() (net.Conn, error) { - c, e := net.Dial(network, proxyAddr) - if e == nil { - p.debugLogger.Printf("Connecting to %s from %s via %s\n", addr, c.LocalAddr(), c.RemoteAddr()) - } - return c, e - } - - connection, err = p.connectToProxy(ctx, proxyUrl, addr, createConnectionFunc) - - if err != nil { - fmt.Println("Failed to connect to Proxy! ", proxyUrl) - } - } else { - p.debugLogger.Println("No Proxy defined for ", addr, "!") - connection, err = net.Dial(network, addr) - } - - return connection, err -} - -// This method takes the given connection and connects to the specified proxy (RFC 2817) while adding proxy authentication (RFC 4559). -func (p *ProxyAuthenticator) connectToProxy(ctx context.Context, proxyURL *url.URL, target string, createConnection func() (net.Conn, error)) (net.Conn, error) { - var err error - var token string - var responseToken string - var connection net.Conn - - if createConnection == nil { - return nil, fmt.Errorf("Given connection must not be nil!") - } - - if proxyURL == nil { - return nil, fmt.Errorf("Given proxyUrl must not be nil!") - } - - if len(target) == 0 { - return nil, fmt.Errorf("Given target address must not be empty!") - } - - if p.acceptedProxyAuthMechanism != NoAuth { - newConnectionRequired := true - authHandler := p.CreateHandler(p.acceptedProxyAuthMechanism) - authHandler.SetLogger(p.debugLogger) - defer authHandler.Close() - - p.debugLogger.Println("Proxy Address:", proxyURL) - - for !authHandler.IsStopped() { - proxyConnectHeader := make(http.Header) - var response *http.Response - var responseError error - - if token, err = authHandler.GetAuthorizationValue(proxyURL, responseToken); err != nil { - err = fmt.Errorf("Failed to retreive Proxy Authorization! %v", err) - } - - if err == nil { - if newConnectionRequired { // open a new connection if required - if connection != nil { - connection.Close() - } - connection, err = createConnection() - } - } - - if err == nil { - if len(token) > 0 { // Add Header if a token is available - proxyConnectHeader.Add(ProxyAuthorizationKey, token) - p.debugLogger.Printf("> %s: %s\n", ProxyAuthorizationKey, token) - newConnectionRequired = false - } else { // Connect without specific header, if this fails, we require a new connection later - p.debugLogger.Printf("> CONNECT without %s", ProxyAuthorizationKey) - newConnectionRequired = true - } - - request := &http.Request{ - Method: "CONNECT", - URL: &url.URL{Opaque: target}, - Host: target, - Header: proxyConnectHeader, - } - - response, responseError = p.SendRequest(ctx, connection, request) - responseToken, err = p.processResponse(authHandler, response, responseError) - } - - if err != nil { - authHandler.Cancel() - - if connection != nil { - connection.Close() - connection = nil - } - } - } - } - - return connection, err -} - -func (p *ProxyAuthenticator) processResponse(authHandler AuthenticationHandlerInterface, response *http.Response, responseError error) (responseToken string, err error) { - if responseError != nil { - err = fmt.Errorf("Failed to CONNECT to proxy! (%v)", responseError) - } else if response != nil && response.StatusCode == 407 { - responseToken, err = p.processResponse407(authHandler, response) - } else if response != nil && response.StatusCode <= 200 && response.StatusCode <= 299 { - authHandler.Succesful() - } else if response != nil { - err = fmt.Errorf("Unexpected HTTP Status Code (%d)", response.StatusCode) - } else { - err = fmt.Errorf("Failed to CONNECT to proxy due to unknown error!") - } - return responseToken, err -} - -func (p *ProxyAuthenticator) processResponse407(authHandler AuthenticationHandlerInterface, response *http.Response) (responseToken string, err error) { - - result := response.Header.Values(ProxyAuthenticateKey) - availableMechanismCount := len(result) - if availableMechanismCount >= 1 { - p.debugLogger.Printf("< %s: %s\n", ProxyAuthenticateKey, result) - availableMechanismList := make(map[AuthenticationMechanism]string, availableMechanismCount) - - for i := range result { - tempMechanism, tempResponseToken := GetMechanismAndToken(result[i]) - availableMechanismList[tempMechanism] = tempResponseToken - - p.debugLogger.Printf(" %d. Detected Mechanism: %s\n", i, StringFromAuthenticationMechanism(tempMechanism)) - - if len(tempResponseToken) != 0 { - p.debugLogger.Printf(" %d. Response Token: %s\n", i, tempResponseToken) - } - } - - responseToken, err = authHandler.Update(availableMechanismList) - - } else { - err = fmt.Errorf("Received 407 but didn't find \"%s\" in the header! (%v)", ProxyAuthenticateKey, response.Header) - } - - return responseToken, err -} - -func (p *ProxyAuthenticator) GetMechanism() AuthenticationMechanism { - return p.acceptedProxyAuthMechanism -} - -func LookupSchemeFromCannonicalAddress(addr string, defaultScheme string) string { - result := defaultScheme - port := "" - tempAddr := strings.Split(addr, ":") - tempAddrLen := len(tempAddr) - if tempAddrLen >= 2 { - port = tempAddr[tempAddrLen-1] - } - - for k, v := range portMap { - if v == port { - result = k - } - } - return result -} - -// the following code is partially taken and adapted from net/http/transport.go ---- - -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// HTTP client implementation. See RFC 7230 through 7235. -// -// This is the low-level Transport implementation of RoundTripper. -// The high-level interface is in client.go. - -func (p *ProxyAuthenticator) SendRequest(ctx context.Context, connection net.Conn, request *http.Request) (*http.Response, error) { - - // If there's no done channel (no deadline or cancellation - // from the caller possible), at least set some (long) - // timeout here. This will make sure we don't block forever - // and leak a goroutine if the connection stops replying - // after the TCP connect. - connectCtx := ctx - if ctx.Done() == nil { - newCtx, cancel := context.WithTimeout(ctx, 1*time.Minute) - defer cancel() - connectCtx = newCtx - } - - didReadResponse := make(chan struct{}) // closed after CONNECT write+read is done or fails - var ( - resp *http.Response - err error // write or read error - ) - // Write the CONNECT request & read the response. - go func() { - defer close(didReadResponse) - err = request.Write(connection) - if err != nil { - return - } - // Okay to use and discard buffered reader here, because - // TLS server will not speak until spoken to. - br := bufio.NewReader(connection) - resp, err = http.ReadResponse(br, request) - }() - select { - case <-connectCtx.Done(): - connection.Close() - <-didReadResponse - return nil, connectCtx.Err() - case <-didReadResponse: - // resp or err now set - } - - if resp != nil { - resp.Body.Close() - } - - return resp, err -} - -var portMap = map[string]string{ - "http": "80", - "https": "443", - "socks5": "1080", -} - -// CanonicalAddr returns url.Host but always with a ":port" suffix -func CanonicalAddr(url *url.URL) string { - addr := url.Hostname() - if v, err := idna.Lookup.ToASCII(addr); err == nil { - addr = v - } - port := url.Port() - if port == "" { - port = portMap[url.Scheme] - } - return net.JoinHostPort(addr, port) -} diff --git a/cliv2/internal/httpauth/proxy_authenticator_test.go b/cliv2/internal/httpauth/proxy_authenticator_test.go deleted file mode 100644 index 4f77e41ff3..0000000000 --- a/cliv2/internal/httpauth/proxy_authenticator_test.go +++ /dev/null @@ -1,513 +0,0 @@ -package httpauth - -import ( - "context" - "fmt" - "net" - "net/http" - "net/url" - "testing" - - "github.com/golang/mock/gomock" - "github.com/snyk/cli/cliv2/internal/httpauth/test/helper" - "github.com/stretchr/testify/assert" -) - -//go:generate $GOPATH/bin/mockgen -source=httpauth.go -destination ./httpauth_generated_mock.go -package httpauth -self_package github.com/snyk/cli/cliv2/internal/httpauth - -func createMockServer() (*helper.MockServer, net.Conn) { - // prepare test data - mockServer := helper.NewMockServer() - go mockServer.Listen() - - connection, _ := net.Dial("tcp", ":"+fmt.Sprint(mockServer.Port)) - - return mockServer, connection -} - -func helper_processResponse407(t *testing.T, success bool, mechanism AuthenticationMechanism, expectedToken string, response *http.Response) { - // prepare test environment - authenticator := NewProxyAuthenticator(mechanism, nil, testLogger) - authHandler := NewHandler(authenticator.acceptedProxyAuthMechanism) - - // run method under test - token, err := authenticator.processResponse407(authHandler, response) - - // check expectations - assert.Equal(t, expectedToken, token) - - if success { - assert.Nil(t, err) - } else { - assert.NotNil(t, err) - } -} - -func helper_processResponse(t *testing.T, success bool, mechanism AuthenticationMechanism, expectedToken string, response *http.Response, responseError error) AuthenticationHandlerInterface { - // prepare test environment - authenticator := NewProxyAuthenticator(mechanism, nil, testLogger) - authHandler := NewHandler(authenticator.acceptedProxyAuthMechanism) - - // run method under test - token, err := authenticator.processResponse(authHandler, response, responseError) - - // check expectations - assert.Equal(t, expectedToken, token) - - if success { - assert.Nil(t, err) - } else { - assert.NotNil(t, err) - } - return authHandler -} - -func helper_DialContext(t *testing.T, success bool, applyExpectations func(*MockAuthenticationHandlerInterface), mechanism AuthenticationMechanism, proxyFunc func(*http.Request) (*url.URL, error), target string) { - context := context.Background() - - ctrl := gomock.NewController(t) - mockedAuthenticationHandler := NewMockAuthenticationHandlerInterface(ctrl) - - // prepare test environment - authenticator := NewProxyAuthenticator(mechanism, proxyFunc, testLogger) - authenticator.CreateHandler = func(mechanism AuthenticationMechanism) AuthenticationHandlerInterface { - return mockedAuthenticationHandler - } - - if applyExpectations != nil { - applyExpectations(mockedAuthenticationHandler) - } - - // run method under test - connection, err := authenticator.DialContext(context, "tcp", target) - - // check expectations - if success { - assert.Nil(t, err) - assert.NotNil(t, connection) - } else { - assert.NotNil(t, err) - assert.Nil(t, connection) - } -} - -func Test_ProxyAuthenticator_processResponse407_fail01(t *testing.T) { - // prepare test data - mechanism := Negotiate - expectedToken := "" - response := &http.Response{} - - helper_processResponse407(t, false, mechanism, expectedToken, response) -} - -func Test_ProxyAuthenticator_processResponse407_fail02(t *testing.T) { - // prepare test data - mechanism := Negotiate - expectedToken := "" - response := &http.Response{ - Header: http.Header{}, - } - response.Header.Add(ProxyAuthenticateKey, "NTLM TlRMTVNTUAACAAAADgAOADgAAAAVgoni/Fy06M1ZvVQAAAAAAAAAAKQApABGAAAABgEAAAAAAA9IAEEATQBNAEUAUgAyAAIADgBIAEEATQBNAEUAUgAyAAEAHABFAEMAMgBBAE0AQQBaAC0AVgBVAEgATABOAFEABAAeAGgAYQBtAG0AZQByADIALgBzAG4AeQBrAC4AaQBvAAMAPABlAGMAMgBhAG0AYQB6AC0AdgB1AGgAbABuAHEALgBoAGEAbQBtAGUAcgAyAC4AcwBuAHkAawAuAGkAbwAHAAgAli6vQTKY2AEAAAAA") - - helper_processResponse407(t, false, mechanism, expectedToken, response) -} - -func Test_ProxyAuthenticator_processResponse407_fail03(t *testing.T) { - // prepare test data - mechanism := Negotiate - expectedToken := "" - response := &http.Response{ - Header: http.Header{}, - } - response.Header.Add(ProxyAuthenticateKey, "") // empty value - - helper_processResponse407(t, false, mechanism, expectedToken, response) -} - -func Test_ProxyAuthenticator_processResponse407_success(t *testing.T) { - // prepare test data - mechanism := Negotiate - expectedToken := "TlRMTVNTUAACAAAADgAOADgAAAAVgoni/Fy06M1ZvVQAAAAAAAAAAKQApABGAAAABgEAAAAAAA9IAEEATQBNAEUAUgAyAAIADgBIAEEATQBNAEUAUgAyAAEAHABFAEMAMgBBAE0AQQBaAC0AVgBVAEgATABOAFEABAAeAGgAYQBtAG0AZQByADIALgBzAG4AeQBrAC4AaQBvAAMAPABlAGMAMgBhAG0AYQB6AC0AdgB1AGgAbABuAHEALgBoAGEAbQBtAGUAcgAyAC4AcwBuAHkAawAuAGkAbwAHAAgAli6vQTKY2AEAAAAA" - response := &http.Response{ - Header: http.Header{}, - } - response.Header.Add(ProxyAuthenticateKey, "Negotiate "+expectedToken) - - helper_processResponse407(t, true, mechanism, expectedToken, response) -} - -func Test_ProxyAuthenticator_processResponse407_success02(t *testing.T) { - // prepare test data - mechanism := Negotiate - expectedToken := "something" - response := &http.Response{ - Header: http.Header{}, - } - - response.Header.Add(ProxyAuthenticateKey, "NTLM") - response.Header.Add(ProxyAuthenticateKey, "NEGOTIATE "+expectedToken) - - helper_processResponse407(t, true, mechanism, expectedToken, response) -} - -func Test_ProxyAuthenticator_processResponse_fail01(t *testing.T) { - // prepare test data - mechanism := Negotiate - expectedToken := "" - responseError := fmt.Errorf("Some downstream error occured!") - response := &http.Response{ - Header: http.Header{}, - } - response.Header.Add(ProxyAuthenticateKey, "Negotiate ") - - helper_processResponse(t, false, mechanism, expectedToken, response, responseError) -} - -func Test_ProxyAuthenticator_processResponse_fail02(t *testing.T) { - // prepare test data - mechanism := Negotiate - expectedToken := "" - responseError := error(nil) - response := &http.Response{ - StatusCode: 500, // unexpected StatusCode - Header: http.Header{}, - } - - helper_processResponse(t, false, mechanism, expectedToken, response, responseError) -} - -func Test_ProxyAuthenticator_processResponse_fail03(t *testing.T) { - // prepare test data - mechanism := Negotiate - expectedToken := "" - responseError := error(nil) - var response *http.Response = nil // response is nil - - helper_processResponse(t, false, mechanism, expectedToken, response, responseError) -} - -func Test_ProxyAuthenticator_processResponse_success407(t *testing.T) { - // prepare test data - mechanism := Negotiate - expectedToken := "TlRMTVNTUAACAAAADgAOADgAAAAVgoni/Fy06M1ZvVQAAAAAAAAAAKQApABGAAAABgEAAAAAAA9IAEEATQBNAEUAUgAyAAIADgBIAEEATQBNAEUAUgAyAAEAHABFAEMAMgBBAE0AQQBaAC0AVgBVAEgATABOAFEABAAeAGgAYQBtAG0AZQByADIALgBzAG4AeQBrAC4AaQBvAAMAPABlAGMAMgBhAG0AYQB6AC0AdgB1AGgAbABuAHEALgBoAGEAbQBtAGUAcgAyAC4AcwBuAHkAawAuAGkAbwAHAAgAli6vQTKY2AEAAAAA" - responseError := error(nil) - response := &http.Response{ - StatusCode: 407, - Header: http.Header{}, - } - response.Header.Add(ProxyAuthenticateKey, "Negotiate "+expectedToken) - - authHandler := helper_processResponse(t, true, mechanism, expectedToken, response, responseError) - assert.False(t, authHandler.IsStopped()) -} - -func Test_ProxyAuthenticator_processResponse_success200(t *testing.T) { - // prepare test data - mechanism := Negotiate - expectedToken := "" - responseError := error(nil) - response := &http.Response{ - StatusCode: 200, - } - - authHandler := helper_processResponse(t, true, mechanism, expectedToken, response, responseError) - assert.True(t, authHandler.IsStopped()) -} - -func Test_ProxyAuthenticator_connectToProxy_fail01(t *testing.T) { - // prepare test data - context := context.Background() - mechanism := Negotiate - proxyUrl := &url.URL{} - target := "" - var createConnectionFunc func() (net.Conn, error) = nil // shouldn't be nil - - // prepare test environment - authenticator := NewProxyAuthenticator(mechanism, nil, testLogger) - - // run method under test - connection, err := authenticator.connectToProxy(context, proxyUrl, target, createConnectionFunc) - - // check expectations - assert.NotNil(t, err) - assert.Nil(t, connection) -} - -func Test_ProxyAuthenticator_connectToProxy_fail02(t *testing.T) { - // prepare test data - context := context.Background() - mechanism := Negotiate - proxyUrl := &url.URL{Opaque: "https://snyk.io"} - target := "" // shouldn't be empty - createConnectionFunc := func() (net.Conn, error) { return nil, nil } - - // prepare test environment - authenticator := NewProxyAuthenticator(mechanism, nil, testLogger) - - // run method under test - connection, err := authenticator.connectToProxy(context, proxyUrl, target, createConnectionFunc) - - // check expectations - assert.NotNil(t, err) - assert.Nil(t, connection) -} - -func Test_ProxyAuthenticator_connectToProxy_fail03(t *testing.T) { - // prepare test data - context := context.Background() - mechanism := Negotiate - var proxyUrl *url.URL = nil // shouldn't be nil - target := "snyk.io:443" - createConnectionFunc := func() (net.Conn, error) { return nil, nil } - - // prepare test environment - authenticator := NewProxyAuthenticator(mechanism, nil, testLogger) - - // run method under test - connection, err := authenticator.connectToProxy(context, proxyUrl, target, createConnectionFunc) - - // check expectations - assert.NotNil(t, err) - assert.Nil(t, connection) -} - -func Test_ProxyAuthenticator_connectToProxy_fail04(t *testing.T) { - mockServer, masterConnection := createMockServer() - - // prepare test data - mockServer.ResponseList = append(mockServer.ResponseList, &http.Response{StatusCode: 407, Header: http.Header{ProxyAuthenticateKey: []string{"Negotiate 123456789"}}}) - mockServer.ResponseList = append(mockServer.ResponseList, &http.Response{StatusCode: 200}) - - context := context.Background() - mechanism := Negotiate - proxyUrl := &url.URL{Opaque: "http://127.0.0.1:3128"} - target := "snyk.io:443" - createConnectionFunc := func() (net.Conn, error) { return masterConnection, nil } - - ctrl := gomock.NewController(t) - mockedAuthenticationHandler := NewMockAuthenticationHandlerInterface(ctrl) - - mockedAuthenticationHandler.EXPECT().IsStopped().Return(false).Times(len(mockServer.ResponseList)) - mockedAuthenticationHandler.EXPECT().IsStopped().Return(true).Times(1) - mockedAuthenticationHandler.EXPECT().GetAuthorizationValue(proxyUrl, "").Times(1).Return("Negotiate TlRMTVNTUAACAAAADgAOADgAAAAVgoni", nil) - mockedAuthenticationHandler.EXPECT().Update(gomock.Any()).Times(1).Return("123456789", nil) - mockedAuthenticationHandler.EXPECT().GetAuthorizationValue(proxyUrl, "123456789").Times(1).Return("", fmt.Errorf("Some library error!")) - mockedAuthenticationHandler.EXPECT().Cancel().Times(1) - mockedAuthenticationHandler.EXPECT().Close().Times(1) - mockedAuthenticationHandler.EXPECT().SetLogger(testLogger).Times(1) - - // prepare test environment - authenticator := NewProxyAuthenticator(mechanism, nil, testLogger) - authenticator.CreateHandler = func(mechanism AuthenticationMechanism) AuthenticationHandlerInterface { - return mockedAuthenticationHandler - } - - // run method under test - connection, err := authenticator.connectToProxy(context, proxyUrl, target, createConnectionFunc) - - // check expectations - assert.NotNil(t, err) - assert.Nil(t, connection) -} - -func Test_ProxyAuthenticator_connectToProxy_success(t *testing.T) { - mockServer, masterConnection := createMockServer() - - // prepare test data - mockServer.ResponseList = append(mockServer.ResponseList, &http.Response{StatusCode: 407, Header: http.Header{ProxyAuthenticateKey: []string{"Negotiate 123456789"}}}) - mockServer.ResponseList = append(mockServer.ResponseList, &http.Response{StatusCode: 407, Header: http.Header{ProxyAuthenticateKey: []string{"Negotiate 10111213141516171819"}}}) - mockServer.ResponseList = append(mockServer.ResponseList, &http.Response{StatusCode: 200}) - - context := context.Background() - mechanism := Negotiate - proxyUrl := &url.URL{Opaque: "http://127.0.0.1:3128"} - target := "snyk.io:443" - createConnectionFunc := func() (net.Conn, error) { return masterConnection, nil } - - ctrl := gomock.NewController(t) - mockedAuthenticationHandler := NewMockAuthenticationHandlerInterface(ctrl) - - mockedAuthenticationHandler.EXPECT().IsStopped().Return(false).Times(len(mockServer.ResponseList)) - mockedAuthenticationHandler.EXPECT().IsStopped().Return(true).Times(1) - mockedAuthenticationHandler.EXPECT().GetAuthorizationValue(proxyUrl, "").Times(1).Return("Negotiate TlRMTVNTUAACAAAADgAOADgAAAAVgoni", nil) - mockedAuthenticationHandler.EXPECT().Update(gomock.Any()).Times(1).Return("123456789", nil) - mockedAuthenticationHandler.EXPECT().GetAuthorizationValue(proxyUrl, "123456789").Times(1).Return("Negotiate TlRMTVNTUAACAAAADgAOADgAAAAVgoni/Fy06M1ZvVQAAAAAAAAAAKQApABGAAAA", nil) - mockedAuthenticationHandler.EXPECT().Update(gomock.Any()).Times(1).Return("10111213141516171819", nil) - mockedAuthenticationHandler.EXPECT().GetAuthorizationValue(proxyUrl, "10111213141516171819").Times(1).Return("Negotiate TlRMTVNTUAACAAAADgAOADgAAAAVgoni/Fy06M1ZvVQAAAAAAAAAAKQApABGAAAABgEAAAAAAA9IAEEATQBNAEUAUgAyAAIADgBIAEEATQBNAEUAUgAyAAEAHABFAEMAMgBBAE0AQQBaAC0AVgBVAEgATABOAFEABAAeAGgAYQBtAG0AZQByADIALgBzAG4AeQBrAC4AaQBvAAMAPABlAGMAMgBhAG0AYQB6AC0AdgB1AGgAbABuAHEALgBoAGEAbQBtAGUAcgAyAC4AcwBuAHkAawAuAGkAbwAHAAgAli6vQTKY2AEAAAAA", nil) - mockedAuthenticationHandler.EXPECT().Succesful().Times(1) - mockedAuthenticationHandler.EXPECT().Close().Times(1) - mockedAuthenticationHandler.EXPECT().SetLogger(testLogger).Times(1) - - // prepare test environment - authenticator := NewProxyAuthenticator(mechanism, nil, testLogger) - authenticator.CreateHandler = func(mechanism AuthenticationMechanism) AuthenticationHandlerInterface { - return mockedAuthenticationHandler - } - - // run method under test - connection, err := authenticator.connectToProxy(context, proxyUrl, target, createConnectionFunc) - - // check expectations - assert.Nil(t, err) - assert.NotNil(t, connection) -} - -func Test_ProxyAuthenticator_DialContext_fail01(t *testing.T) { - mechanism := Negotiate - proxyUrl, _ := url.Parse("http://localhost:12") // used random not existing port - target := "snyk.io:443" - proxyFunc := func(*http.Request) (*url.URL, error) { return proxyUrl, nil } - - expectations := func(mockedAuthenticationHandler *MockAuthenticationHandlerInterface) { - mockedAuthenticationHandler.EXPECT().IsStopped().Return(false).Times(1) - mockedAuthenticationHandler.EXPECT().IsStopped().Return(true).Times(1) - mockedAuthenticationHandler.EXPECT().GetAuthorizationValue(proxyUrl, "").Times(1).Return("Negotiate TlRMTVNTUAACAAAADgAOADgAAAAVgoni", nil) - mockedAuthenticationHandler.EXPECT().Cancel().Times(1) - mockedAuthenticationHandler.EXPECT().Close().Times(1) - mockedAuthenticationHandler.EXPECT().SetLogger(testLogger).Times(1) - } - - helper_DialContext(t, false, expectations, mechanism, proxyFunc, target) -} - -func Test_ProxyAuthenticator_DialContext_fail02(t *testing.T) { - mechanism := Negotiate - proxyUrl, _ := url.Parse("http://localhost:123") - target := "snyk.io:7831" // used random not existing port which will not find an appropriate proxy - proxyFunc := func(*http.Request) (*url.URL, error) { return proxyUrl, nil } - - expectations := func(mockedAuthenticationHandler *MockAuthenticationHandlerInterface) { - mockedAuthenticationHandler.EXPECT().IsStopped().Return(false).Times(1) - mockedAuthenticationHandler.EXPECT().IsStopped().Return(true).Times(1) - mockedAuthenticationHandler.EXPECT().GetAuthorizationValue(proxyUrl, "").Times(1).Return("Negotiate TlRMTVNTUAACAAAADgAOADgAAAAVgoni", nil) - mockedAuthenticationHandler.EXPECT().Cancel().Times(1) - mockedAuthenticationHandler.EXPECT().Close().Times(1) - mockedAuthenticationHandler.EXPECT().SetLogger(testLogger).Times(1) - } - - helper_DialContext(t, false, expectations, mechanism, proxyFunc, target) -} - -func Test_ProxyAuthenticator_DialContext_fail03(t *testing.T) { - mechanism := Negotiate - proxyUrl, _ := url.Parse("http://localhost:123") - target := "snyk.io:443" - proxyFunc := func(*http.Request) (*url.URL, error) { return proxyUrl, fmt.Errorf("Some random error") } - - helper_DialContext(t, false, nil, mechanism, proxyFunc, target) -} - -// Test case: Negotiate enabled, proxy address specified, doing 3 message authentication similar to NTLM (using spnego provider mock) -func Test_ProxyAuthenticator_DialContext_success(t *testing.T) { - mockServer, _ := createMockServer() - - // prepare test data - mockServer.ResponseList = append(mockServer.ResponseList, &http.Response{StatusCode: 407, Header: http.Header{ProxyAuthenticateKey: []string{"Negotiate " + NTML_02_CHALLENGE}}}) - mockServer.ResponseList = append(mockServer.ResponseList, &http.Response{StatusCode: 200}) - - mechanism := Negotiate - proxyUrl, _ := url.Parse("http://localhost:" + fmt.Sprint(mockServer.Port)) - target := "snyk.io:443" - proxyFunc := func(*http.Request) (*url.URL, error) { return proxyUrl, nil } - - spnegoProviderMock := NewMockSpnegoProvider(gomock.NewController(t)) - defer spnegoProviderMock.ctrl.Finish() - spnegoProviderMock.EXPECT().GetToken(proxyUrl, "").Times(1).Return(NTML_01_INITIALMESSAGE, false, nil) - spnegoProviderMock.EXPECT().GetToken(proxyUrl, NTML_02_CHALLENGE).Times(1).Return(NTML_03_RESPONSE, true, nil) - spnegoProviderMock.EXPECT().SetLogger(testLogger) - spnegoProviderMock.EXPECT().Close().Times(1) - - // prepare test environment - authenticator := NewProxyAuthenticator(mechanism, proxyFunc, testLogger) - authenticator.CreateHandler = func(mechanism AuthenticationMechanism) AuthenticationHandlerInterface { - authHandler := NewHandler(mechanism) - authHandler.SetSpnegoProvider(spnegoProviderMock) - return authHandler - } - - // run method under test - connection, err := authenticator.DialContext(context.Background(), "tcp", target) - - // check expectations - assert.Nil(t, err) - assert.NotNil(t, connection) -} - -// Test case: AnyAuth enabled, proxy address specified, doing 3 message authentication similar to NTLM (using spnego provider mock) -func Test_ProxyAuthenticator_DialContext_success02(t *testing.T) { - mockServer, _ := createMockServer() - - // prepare test data - mockServer.ResponseList = append(mockServer.ResponseList, &http.Response{StatusCode: 407, Header: http.Header{ProxyAuthenticateKey: []string{"NTLM", "Negotiate"}}}) - mockServer.ResponseList = append(mockServer.ResponseList, &http.Response{StatusCode: 407, Header: http.Header{ProxyAuthenticateKey: []string{"Negotiate " + NTML_02_CHALLENGE}}}) - mockServer.ResponseList = append(mockServer.ResponseList, &http.Response{StatusCode: 200}) - - mechanism := AnyAuth - proxyUrl, _ := url.Parse("http://localhost:" + fmt.Sprint(mockServer.Port)) - target := "snyk.io:443" - proxyFunc := func(*http.Request) (*url.URL, error) { return proxyUrl, nil } - - spnegoProviderMock := NewMockSpnegoProvider(gomock.NewController(t)) - defer spnegoProviderMock.ctrl.Finish() - spnegoProviderMock.EXPECT().GetToken(proxyUrl, "").Times(1).Return(NTML_01_INITIALMESSAGE, false, nil) - spnegoProviderMock.EXPECT().GetToken(proxyUrl, NTML_02_CHALLENGE).Times(1).Return(NTML_03_RESPONSE, true, nil) - spnegoProviderMock.EXPECT().SetLogger(testLogger) - spnegoProviderMock.EXPECT().Close().Times(1) - - // prepare test environment - authenticator := NewProxyAuthenticator(mechanism, proxyFunc, testLogger) - authenticator.CreateHandler = func(mechanism AuthenticationMechanism) AuthenticationHandlerInterface { - authHandler := NewHandler(mechanism) - authHandler.SetSpnegoProvider(spnegoProviderMock) - return authHandler - } - - // run method under test - connection, err := authenticator.DialContext(context.Background(), "tcp", target) - - // check expectations - assert.Nil(t, err) - assert.NotNil(t, connection) -} - -// Test case: AnyAuth enabled, NO proxy address specified, normal connection will be established (using spnego provider mock) -func Test_ProxyAuthenticator_DialContext_success03(t *testing.T) { - mechanism := AnyAuth - target := "snyk.io:443" - var proxyFunc func(*http.Request) (*url.URL, error) // no proxy configured should just return the tcp connection - - helper_DialContext(t, true, nil, mechanism, proxyFunc, target) -} - -// Test case: AnyAuth enabled, proxy address specified, proxy doesn't require authentication (using spnego provider mock) -func Test_ProxyAuthenticator_DialContext_success04(t *testing.T) { - mockServer, _ := createMockServer() - - // prepare test data - mockServer.ResponseList = append(mockServer.ResponseList, &http.Response{StatusCode: 200}) - - mechanism := AnyAuth - proxyUrl, _ := url.Parse("http://localhost:" + fmt.Sprint(mockServer.Port)) - target := "snyk.io:443" - proxyFunc := func(*http.Request) (*url.URL, error) { return proxyUrl, nil } - - spnegoProviderMock := NewMockSpnegoProvider(gomock.NewController(t)) - defer spnegoProviderMock.ctrl.Finish() - spnegoProviderMock.EXPECT().SetLogger(testLogger) - spnegoProviderMock.EXPECT().Close().Times(1) - - // prepare test environment - authenticator := NewProxyAuthenticator(mechanism, proxyFunc, testLogger) - authenticator.CreateHandler = func(mechanism AuthenticationMechanism) AuthenticationHandlerInterface { - authHandler := NewHandler(mechanism) - authHandler.SetSpnegoProvider(spnegoProviderMock) - return authHandler - } - - // run method under test - connection, err := authenticator.DialContext(context.Background(), "tcp", target) - - // check expectations - assert.Nil(t, err) - assert.NotNil(t, connection) -} diff --git a/cliv2/internal/httpauth/spnego.go b/cliv2/internal/httpauth/spnego.go deleted file mode 100644 index 300c669a01..0000000000 --- a/cliv2/internal/httpauth/spnego.go +++ /dev/null @@ -1,61 +0,0 @@ -package httpauth - -import ( - "encoding/asn1" - "encoding/base64" - "fmt" - "log" - "net/url" - "reflect" - "strings" - - "github.com/jcmturner/gokrb5/v8/gssapi" -) - -const ( - NTLMSSP_NAME string = "NTLMSSP" - SPNEGO_NAME string = string(gssapi.OIDSPNEGO) -) - -type SpnegoProvider interface { - GetToken(url *url.URL, responseToken string) (string, bool, error) - Close() error - SetLogger(logger *log.Logger) -} - -func IsNTLMToken(token string) bool { - isNtlm := strings.Contains(token, "TlRMTVNTU") - return isNtlm -} - -func GetMechanismsFromHttpFieldValue(token string) ([]string, error) { - var result []string - var err error - - if strings.Contains(token, " ") { - temp := strings.Split(token, " ") - token = temp[1] - } - - if IsNTLMToken(token) { - result = append(result, NTLMSSP_NAME) - } else { - var decodedToken []byte - decodedToken, err = base64.StdEncoding.DecodeString(token) - if err == nil { - var oid asn1.ObjectIdentifier - _, err = asn1.UnmarshalWithParams(decodedToken, &oid, fmt.Sprintf("application,explicit,tag:%v", 0)) - - if reflect.DeepEqual(oid, asn1.ObjectIdentifier(gssapi.OIDSPNEGO.OID())) { - result = append(result, SPNEGO_NAME) - } - - } - - if err != nil { - fmt.Println(err) - } - } - - return result, err -} diff --git a/cliv2/internal/httpauth/spnego_generated_mock.go b/cliv2/internal/httpauth/spnego_generated_mock.go deleted file mode 100644 index d098b36d67..0000000000 --- a/cliv2/internal/httpauth/spnego_generated_mock.go +++ /dev/null @@ -1,78 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: spnego.go - -// Package httpauth is a generated GoMock package. -package httpauth - -import ( - log "log" - url "net/url" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" -) - -// MockSpnegoProvider is a mock of SpnegoProvider interface. -type MockSpnegoProvider struct { - ctrl *gomock.Controller - recorder *MockSpnegoProviderMockRecorder -} - -// MockSpnegoProviderMockRecorder is the mock recorder for MockSpnegoProvider. -type MockSpnegoProviderMockRecorder struct { - mock *MockSpnegoProvider -} - -// NewMockSpnegoProvider creates a new mock instance. -func NewMockSpnegoProvider(ctrl *gomock.Controller) *MockSpnegoProvider { - mock := &MockSpnegoProvider{ctrl: ctrl} - mock.recorder = &MockSpnegoProviderMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockSpnegoProvider) EXPECT() *MockSpnegoProviderMockRecorder { - return m.recorder -} - -// Close mocks base method. -func (m *MockSpnegoProvider) Close() error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Close") - ret0, _ := ret[0].(error) - return ret0 -} - -// Close indicates an expected call of Close. -func (mr *MockSpnegoProviderMockRecorder) Close() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockSpnegoProvider)(nil).Close)) -} - -// GetToken mocks base method. -func (m *MockSpnegoProvider) GetToken(url *url.URL, responseToken string) (string, bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetToken", url, responseToken) - ret0, _ := ret[0].(string) - ret1, _ := ret[1].(bool) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 -} - -// GetToken indicates an expected call of GetToken. -func (mr *MockSpnegoProviderMockRecorder) GetToken(url, responseToken interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetToken", reflect.TypeOf((*MockSpnegoProvider)(nil).GetToken), url, responseToken) -} - -// SetLogger mocks base method. -func (m *MockSpnegoProvider) SetLogger(logger *log.Logger) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetLogger", logger) -} - -// SetLogger indicates an expected call of SetLogger. -func (mr *MockSpnegoProviderMockRecorder) SetLogger(logger interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLogger", reflect.TypeOf((*MockSpnegoProvider)(nil).SetLogger), logger) -} diff --git a/cliv2/internal/httpauth/spnego_nonwindows.go b/cliv2/internal/httpauth/spnego_nonwindows.go deleted file mode 100644 index 406986c43a..0000000000 --- a/cliv2/internal/httpauth/spnego_nonwindows.go +++ /dev/null @@ -1,121 +0,0 @@ -//go:build linux || darwin -// +build linux darwin - -package httpauth - -import ( - "encoding/base64" - "fmt" - "io" - "log" - "net/url" - "os" - "os/user" - "strings" - - "github.com/jcmturner/gokrb5/v8/client" - "github.com/jcmturner/gokrb5/v8/config" - "github.com/jcmturner/gokrb5/v8/credentials" - "github.com/jcmturner/gokrb5/v8/krberror" - "github.com/jcmturner/gokrb5/v8/spnego" -) - -type NonwindowsSpnegoProvider struct { - logger *log.Logger - configPath string - cachePath string - config *config.Config - client *spnego.SPNEGO -} - -func SpnegoProviderInstance() SpnegoProvider { - s := &NonwindowsSpnegoProvider{} - s.initDefaultConfiguration() - return s -} - -func (s *NonwindowsSpnegoProvider) initDefaultConfiguration() { - // logger - s.logger = log.New(io.Discard, "", 0) - - // configuration location - s.configPath = os.Getenv("KRB5_CONFIG") - if _, err := os.Stat(s.configPath); os.IsNotExist(err) { - s.configPath = "/etc/krb5.conf" - } - - // cache location - user, err := user.Current() - if err == nil { - s.cachePath = "/tmp/krb5cc_" + user.Uid - cacheName := os.Getenv("KRB5CCNAME") - if strings.HasPrefix(cacheName, "FILE:") { - s.cachePath = strings.SplitN(cacheName, ":", 2)[1] - } - } else { - s.logger.Println("Failed to get current user! ", err) - } - -} - -func (s *NonwindowsSpnegoProvider) Close() error { - return nil -} - -func (s *NonwindowsSpnegoProvider) SetLogger(logger *log.Logger) { - s.logger = logger -} - -func (s *NonwindowsSpnegoProvider) init(url *url.URL) ([]byte, error) { - hostname := url.Hostname() - spn := "HTTP/" + hostname - token := []byte{} - var err error - - s.logger.Printf("krb5 configuration file: %s", s.configPath) - s.config, err = config.Load(s.configPath) - if err != nil { - return token, err - } - - s.logger.Printf("krb5 cache file: %s", s.cachePath) - cache, err := credentials.LoadCCache(s.cachePath) - if err != nil { - return token, err - } - - krb5client, err := client.NewFromCCache(cache, s.config, client.DisablePAFXFAST(true)) - - s.client = spnego.SPNEGOClient(krb5client, spn) - - tokenObject, err := s.client.InitSecContext() - if err != nil { - return token, fmt.Errorf("could not initialize context: %v", err) - } - - token, err = tokenObject.Marshal() - if err != nil { - return token, krberror.Errorf(err, krberror.EncodingError, "could not marshal SPNEGO") - } - - return token, err -} - -func (s *NonwindowsSpnegoProvider) GetToken(url *url.URL, responseToken string) (string, bool, error) { - var err error - var token []byte - var encodedToken string - done := false - - if s.client == nil { - token, err = s.init(url) - } else { - err = fmt.Errorf("NonwindowsSpnegoProvider.update() is not yet implemented. Only preemptive authentication is supported!") - } - - if len(token) > 0 { - encodedToken = base64.StdEncoding.EncodeToString(token) - } - - return encodedToken, done, err -} diff --git a/cliv2/internal/httpauth/spnego_test.go b/cliv2/internal/httpauth/spnego_test.go deleted file mode 100644 index 0a42c077cf..0000000000 --- a/cliv2/internal/httpauth/spnego_test.go +++ /dev/null @@ -1,169 +0,0 @@ -package httpauth - -import ( - "fmt" - "net/url" - "os" - "os/exec" - "path/filepath" - "runtime" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -//go:generate $GOPATH/bin/mockgen -source=spnego.go -destination ./spnego_generated_mock.go -package httpauth -self_package github.com/snyk/cli/cliv2/internal/httpauth - -func fixturePath() string { - path, _ := filepath.Abs(filepath.Join("..", "..", "internal", "httpauth", "test", "fixtures")) - return path -} - -func dockerComposeFile() string { - path := filepath.Join(fixturePath(), "squid_environment", "docker-compose.yml") - return path -} - -func scriptsPath() string { - path := filepath.Join(fixturePath(), "squid_environment", "scripts") - return path -} - -func hasDockerInstalled() bool { - result := false - cmd := exec.Command("docker-compose", "--version") - err := cmd.Run() - if err == nil { - result = true - } - return result -} - -func runTestUsingExternalAuthLibrary() bool { - result := false - os := runtime.GOOS - if os == "windows" { - result = true - } else { - result = hasDockerInstalled() - } - return result -} - -func runDockerCompose(arg ...string) { - cmd := exec.Command("docker-compose", arg...) - cmd.Env = os.Environ() - cmd.Env = append(cmd.Env, "HTTP_PROXY_PORT=3128") - cmd.Env = append(cmd.Env, "PROXY_HOSTNAME=proxy.snyk.local") - cmd.Env = append(cmd.Env, "CONTAINER_NAME=spnego_test") - cmd.Env = append(cmd.Env, "SCRIPTS_PATH="+scriptsPath()) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - run := func() { - err := cmd.Run() - if err != nil { - fmt.Println(err) - } - } - run() -} - -func startProxyEnvironment() { - stopProxyEnvironment() - runDockerCompose("--file", dockerComposeFile(), "up", "--build", "--detach") -} - -func stopProxyEnvironment() { - runDockerCompose("--file", dockerComposeFile(), "down") -} - -func waitForFile(filename string, timeout time.Duration) { - start := time.Now() - for { - _, err := os.Stat(filename) - if !os.IsNotExist(err) { - break - } - - if time.Since(start) >= timeout { - fmt.Println("waitForFile() - timeout", filename) - break - } - - time.Sleep(time.Second) - - } -} - -func Test_IsNTLMToken(t *testing.T) { - ntlmToken := "TlRMTVNTUAACAAAADgAOADgAAAAVgoni/Fy06M1ZvVQAAAAAAAAAAKQApABGAAAABgEAAAAAAA9IAEEATQBNAEUAUgAyAAIADgBIAEEATQBNAEUAUgAyAAEAHABFAEMAMgBBAE0AQQBaAC0AVgBVAEgATABOAFEABAAeAGgAYQBtAG0AZQByADIALgBzAG4AeQBrAC4AaQBvAAMAPABlAGMAMgBhAG0AYQB6AC0AdgB1AGgAbABuAHEALgBoAGEAbQBtAGUAcgAyAC4AcwBuAHkAawAuAGkAbwAHAAgAli6vQTKY2AEAAAAA" - assert.True(t, IsNTLMToken(ntlmToken)) - - nonNtlmToken := "YIIIOgYGKwYBBQUCoIIILjCCCCqgMDAuBgkqhkiC9xIBAgIGCSqGSIb3EgECAgYKKwYBBAGCNwICHgYKKwYBBAGCNwICCqKCB/QEggfwYIIH7AYJKoZIhvcSAQICAQBuggfbMIIH16ADAgEFoQMCAQ6iBwMFACAAAACjggXwYYIF7DCCBeigAwIBBaERGw9IQU1NRVIyLlNOWUsuSU+iMTAvoAMCAQKhKDAmGwRIVFRQGx5FQzJBTUFaLXZ1SGxOUS5oYW1tZXIyLnNueWsuaW+jggWZMIIFlaADAgESoQMCARGiggWHBIIFg+D23RW9siubTtOIG40J97PP44yP8iJ77Sl7k/5D4m+DMENFD1yfxY6JbJYHA34EF0TbE4/Dz+OTSWOS8vPACYiunkZrEbtHa6gx2K+Lp4ogo0UVmPfRjkokvFZNgeRfDYhCg3WPXffuQOpcT209gz/StKRQtaE7O5TyPIbWpzXjtxyuIWisLM5G5OgR4nOPJ+8VGwA6DEP/xOfzOheqmGELv+/14uY1SeI2EiqZDpQVl/ZP0p6MkxyR3I0o1xn7u2jgQfMnlN1hFcTwi6lfh1XoPT+3ZeIOc8J/DS74vX2jElpl6gqBC4vB5FrcB7do4L2XI6bUfgiNT9uhpgcb0kOu4D2sPQaI3/TDPByknJCPK6YkVlO/l1cXJ158uebfLWWUgbK4XJjLU9K7tk2wqtNvdkmEXkJOcbHFvo+4Bda1OhcgFvpjuCSscSLjnK2PwZv51qlA3ozK93v/1wjAWJrgGTu9KB5MraZzWZF8XZz+yrWP710WZ35ohHoR2tFK8GdukoH1ZO0jts0VT/W0zk+SyatJ3TAev/HU6R7sTKF/x8pSTlzOa9La7gyuHKOUxUlkt23YJvZKQgdEu/585iGy0o0w3MwVWb3CsLxr2URjc9Z4r693YNBdQ2xPjDdL2pzvaMnswHr97mOR1fnemuIDkL26wKKjKzPdhNqB0aed1z/saYou/5nkDAfGjMzI4Pw58zUHgOiOzwuAZF5bjKUMn5kQcarRNGVuZFJ6jB89r1JuHt/HUQ1Ie5ZsYIq1oPGyeCZy40EwOHpuy9Ks88BnzNfi7kMgb8FKgZL1nGzR4rqucQn6OGjdwFXk2624b/JYztPlsmRrzsHXp6lampUxxDQN5KqYPzAawC6/G5SdqFw3Wf8rDW9b+claN3dzEj8kAHHlqrJx4By5X+HTwspHtZNCCOwrJp7rcXw1+5sLdx/XAYI3rSFaIAO9VlZe5E1uml/uToawlWZ5phtO2H5GwxadtG0vIw8MdFpy2UiEocYZuE1aCHYCLjXZokl4tsqIeXndsEgCWq5IpZ2PLQr14XUQHjOu8y2tPpw3sklxBIgXxt1sSpjOWMLROPXkJRI2QriVuhoOoGgIyi4wKbTC0f0tBDjv2AGKYmOZpaHW8hGyJ4YzTkxq+eGL5aLy457Ag6JtAIkUW9RUiFIMQoIKdq0TP/875qcE3xFjoRrS46e4P38IfXEmpRmJih1f4/R0nPZ3sgisgnK2LthxzUuewzBTxghadmLtj0QopOv/uCaFhwObxuE7hzVjriQnIl1rw/rpL+4aNZpinexGXtW7lawi/M4ANJPAusDxJ1A2AeoWtcf7AzLACHK/3RUAXRfrhdzoEh1Lt+tC2LM0qUdASxJ+UgZoABqg49feQ1TfByHxE/H0aJOEL81TDkqfVr59LMTtxPiYsMWm2uKXQIxiyydGYLKQhPm3GoCW0JZfgjm/tmsKG0dNPgruVjJz52zvgy5+5rYqmTBUeJRnT3zigT7ZVbmiHqeQJndMcMvLcrl3Z7o7OsMuynCyNMccfhtLlMQgwPhMGuRDZsNDwnduJk4jzg/qgP1fLvCTS22kegaF/+tIM3A4cyh7SJugkP7jN/P2OzFZV11XG8LO0GCvLVq3XYGU3v20lSpIEGJfcY6utJ4e+ButmDj7tw4IxFJxkoM4ciee/rLzzQD8BaOuqvofcTwQgWBEuHYPs5m4rHFE7xwLLiIIwlOD6NF7LSSztC/y9eV+Jdd9CuyuqqqOGLLw+E0jW9eXm1RukOqwue7r3109+USkF+ebA3SiTwGZwwXVLb3KptA3KCygZZAlfAsvK3UO96tXCYxEk6M/QIMtyt5xXwrrKtNW3HF3okqGAWOlhyUPq1W3wHS1zeMow+GkggHMMIIByKADAgESooIBvwSCAbuire4ijXcXCqxnXhwOxHBHAML3kvrdUnrAm2egVIRFxo22U5/yE4fCU8nsDty14GyXtDyZmabSXFU3WMSruXs7vkldQiCj0n7+jwFRKbtgBh6+bk0JP+sMK8vIHe1/TCNjiSpyJY2Xj69qyG4y3uYmr77DR17CEFnDbnlPFwrVC2zTWUDfDx/p98/d3Z7cQ3JnfdX8SRmM2zJv9pJ1hWNe73moYY1940TJmsYRq3eFr+BxfvvQabDoc1BC7n+1weNUxhZf9SVUl8WFElICazqhwDic//wfuc9qV3oaypIKhykmThXJddsqlckMbcKQjEO8CC1nnUnbU4WeQO0+c8sQrzcHCZQqdGv+5N4XBQ+AAv4p0K+o35OLqg+P+rsxC01ug4m2Q5AwL65dz3Wpa4j8MBTFTIo6RI3Hr/i2Li3MsPkxJ78eFWnoHgaDz+ULQ2HxkvQDTaAlQs4EN86FxlLJ1CYyN+aYtbiiBCO7O7AgwzLN3YPoF9kkszeKFqamsy2wZ6j5Lqte/04piZkY18EZ6z5XkrT+enntabIyi9qkgvHh+VDmV7NXnzjrJ/6GLwNQuNx+Vq7FJwR6lw==" - assert.False(t, IsNTLMToken(nonNtlmToken)) -} - -func Test_GetMechanismsFromHttpFieldValue_NTLM(t *testing.T) { - ntlmToken := "TlRMTVNTUAACAAAADgAOADgAAAAVgoni/Fy06M1ZvVQAAAAAAAAAAKQApABGAAAABgEAAAAAAA9IAEEATQBNAEUAUgAyAAIADgBIAEEATQBNAEUAUgAyAAEAHABFAEMAMgBBAE0AQQBaAC0AVgBVAEgATABOAFEABAAeAGgAYQBtAG0AZQByADIALgBzAG4AeQBrAC4AaQBvAAMAPABlAGMAMgBhAG0AYQB6AC0AdgB1AGgAbABuAHEALgBoAGEAbQBtAGUAcgAyAC4AcwBuAHkAawAuAGkAbwAHAAgAli6vQTKY2AEAAAAA" - expected := NTLMSSP_NAME - actual, err := GetMechanismsFromHttpFieldValue(ntlmToken) - assert.Nil(t, err) - assert.Equal(t, actual[0], expected) -} - -func Test_GetMechanismsFromHttpFieldValue_NTLM_Negotiate(t *testing.T) { - ntlmToken := "Negotiate TlRMTVNTUAACAAAADgAOADgAAAAVgoni/Fy06M1ZvVQAAAAAAAAAAKQApABGAAAABgEAAAAAAA9IAEEATQBNAEUAUgAyAAIADgBIAEEATQBNAEUAUgAyAAEAHABFAEMAMgBBAE0AQQBaAC0AVgBVAEgATABOAFEABAAeAGgAYQBtAG0AZQByADIALgBzAG4AeQBrAC4AaQBvAAMAPABlAGMAMgBhAG0AYQB6AC0AdgB1AGgAbABuAHEALgBoAGEAbQBtAGUAcgAyAC4AcwBuAHkAawAuAGkAbwAHAAgAli6vQTKY2AEAAAAA" - expected := NTLMSSP_NAME - actual, err := GetMechanismsFromHttpFieldValue(ntlmToken) - assert.Nil(t, err) - assert.Contains(t, actual[0], expected) -} - -func Test_GetMechanismsFromHttpFieldValue_Multiple(t *testing.T) { - ntlmToken := "YIIIOgYGKwYBBQUCoIIILjCCCCqgMDAuBgkqhkiC9xIBAgIGCSqGSIb3EgECAgYKKwYBBAGCNwICHgYKKwYBBAGCNwICCqKCB/QEggfwYIIH7AYJKoZIhvcSAQICAQBuggfbMIIH16ADAgEFoQMCAQ6iBwMFACAAAACjggXwYYIF7DCCBeigAwIBBaERGw9IQU1NRVIyLlNOWUsuSU+iMTAvoAMCAQKhKDAmGwRIVFRQGx5FQzJBTUFaLXZ1SGxOUS5oYW1tZXIyLnNueWsuaW+jggWZMIIFlaADAgESoQMCARGiggWHBIIFg+D23RW9siubTtOIG40J97PP44yP8iJ77Sl7k/5D4m+DMENFD1yfxY6JbJYHA34EF0TbE4/Dz+OTSWOS8vPACYiunkZrEbtHa6gx2K+Lp4ogo0UVmPfRjkokvFZNgeRfDYhCg3WPXffuQOpcT209gz/StKRQtaE7O5TyPIbWpzXjtxyuIWisLM5G5OgR4nOPJ+8VGwA6DEP/xOfzOheqmGELv+/14uY1SeI2EiqZDpQVl/ZP0p6MkxyR3I0o1xn7u2jgQfMnlN1hFcTwi6lfh1XoPT+3ZeIOc8J/DS74vX2jElpl6gqBC4vB5FrcB7do4L2XI6bUfgiNT9uhpgcb0kOu4D2sPQaI3/TDPByknJCPK6YkVlO/l1cXJ158uebfLWWUgbK4XJjLU9K7tk2wqtNvdkmEXkJOcbHFvo+4Bda1OhcgFvpjuCSscSLjnK2PwZv51qlA3ozK93v/1wjAWJrgGTu9KB5MraZzWZF8XZz+yrWP710WZ35ohHoR2tFK8GdukoH1ZO0jts0VT/W0zk+SyatJ3TAev/HU6R7sTKF/x8pSTlzOa9La7gyuHKOUxUlkt23YJvZKQgdEu/585iGy0o0w3MwVWb3CsLxr2URjc9Z4r693YNBdQ2xPjDdL2pzvaMnswHr97mOR1fnemuIDkL26wKKjKzPdhNqB0aed1z/saYou/5nkDAfGjMzI4Pw58zUHgOiOzwuAZF5bjKUMn5kQcarRNGVuZFJ6jB89r1JuHt/HUQ1Ie5ZsYIq1oPGyeCZy40EwOHpuy9Ks88BnzNfi7kMgb8FKgZL1nGzR4rqucQn6OGjdwFXk2624b/JYztPlsmRrzsHXp6lampUxxDQN5KqYPzAawC6/G5SdqFw3Wf8rDW9b+claN3dzEj8kAHHlqrJx4By5X+HTwspHtZNCCOwrJp7rcXw1+5sLdx/XAYI3rSFaIAO9VlZe5E1uml/uToawlWZ5phtO2H5GwxadtG0vIw8MdFpy2UiEocYZuE1aCHYCLjXZokl4tsqIeXndsEgCWq5IpZ2PLQr14XUQHjOu8y2tPpw3sklxBIgXxt1sSpjOWMLROPXkJRI2QriVuhoOoGgIyi4wKbTC0f0tBDjv2AGKYmOZpaHW8hGyJ4YzTkxq+eGL5aLy457Ag6JtAIkUW9RUiFIMQoIKdq0TP/875qcE3xFjoRrS46e4P38IfXEmpRmJih1f4/R0nPZ3sgisgnK2LthxzUuewzBTxghadmLtj0QopOv/uCaFhwObxuE7hzVjriQnIl1rw/rpL+4aNZpinexGXtW7lawi/M4ANJPAusDxJ1A2AeoWtcf7AzLACHK/3RUAXRfrhdzoEh1Lt+tC2LM0qUdASxJ+UgZoABqg49feQ1TfByHxE/H0aJOEL81TDkqfVr59LMTtxPiYsMWm2uKXQIxiyydGYLKQhPm3GoCW0JZfgjm/tmsKG0dNPgruVjJz52zvgy5+5rYqmTBUeJRnT3zigT7ZVbmiHqeQJndMcMvLcrl3Z7o7OsMuynCyNMccfhtLlMQgwPhMGuRDZsNDwnduJk4jzg/qgP1fLvCTS22kegaF/+tIM3A4cyh7SJugkP7jN/P2OzFZV11XG8LO0GCvLVq3XYGU3v20lSpIEGJfcY6utJ4e+ButmDj7tw4IxFJxkoM4ciee/rLzzQD8BaOuqvofcTwQgWBEuHYPs5m4rHFE7xwLLiIIwlOD6NF7LSSztC/y9eV+Jdd9CuyuqqqOGLLw+E0jW9eXm1RukOqwue7r3109+USkF+ebA3SiTwGZwwXVLb3KptA3KCygZZAlfAsvK3UO96tXCYxEk6M/QIMtyt5xXwrrKtNW3HF3okqGAWOlhyUPq1W3wHS1zeMow+GkggHMMIIByKADAgESooIBvwSCAbuire4ijXcXCqxnXhwOxHBHAML3kvrdUnrAm2egVIRFxo22U5/yE4fCU8nsDty14GyXtDyZmabSXFU3WMSruXs7vkldQiCj0n7+jwFRKbtgBh6+bk0JP+sMK8vIHe1/TCNjiSpyJY2Xj69qyG4y3uYmr77DR17CEFnDbnlPFwrVC2zTWUDfDx/p98/d3Z7cQ3JnfdX8SRmM2zJv9pJ1hWNe73moYY1940TJmsYRq3eFr+BxfvvQabDoc1BC7n+1weNUxhZf9SVUl8WFElICazqhwDic//wfuc9qV3oaypIKhykmThXJddsqlckMbcKQjEO8CC1nnUnbU4WeQO0+c8sQrzcHCZQqdGv+5N4XBQ+AAv4p0K+o35OLqg+P+rsxC01ug4m2Q5AwL65dz3Wpa4j8MBTFTIo6RI3Hr/i2Li3MsPkxJ78eFWnoHgaDz+ULQ2HxkvQDTaAlQs4EN86FxlLJ1CYyN+aYtbiiBCO7O7AgwzLN3YPoF9kkszeKFqamsy2wZ6j5Lqte/04piZkY18EZ6z5XkrT+enntabIyi9qkgvHh+VDmV7NXnzjrJ/6GLwNQuNx+Vq7FJwR6lw==" - expected := SPNEGO_NAME - actual, err := GetMechanismsFromHttpFieldValue(ntlmToken) - assert.Nil(t, err) - assert.Contains(t, actual, expected) -} - -// This is a very simplistic test for basic coverage. It is not supposed to recreate a functional setup -func Test_GetToken(t *testing.T) { - - if !runTestUsingExternalAuthLibrary() { - t.Skip("This test can't be run in this environment.") - } - - dockerInstalled := hasDockerInstalled() - if dockerInstalled { - startProxyEnvironment() - } - - config := filepath.Join(fixturePath(), "squid_environment", "scripts", "krb5.conf") - cache := filepath.Join(fixturePath(), "squid_environment", "scripts", "krb5_cache") - waitForFile(config, time.Second*30) - - os.Setenv("KRB5CCNAME", "FILE:"+cache) - os.Setenv("KRB5_CONFIG", config) - - url, _ := url.Parse("https://localhost:3128") - initialToken := "" - expectedDone := false - - provider := SpnegoProviderInstance() - actualToken, done, err := provider.GetToken(url, initialToken) - - assert.NotEmpty(t, actualToken) - assert.Equal(t, expectedDone, done) - assert.Nil(t, err) - - fmt.Println(actualToken) - - if dockerInstalled { - stopProxyEnvironment() - } - - os.Remove(config) - os.Remove(cache) -} diff --git a/cliv2/internal/httpauth/spnego_windows.go b/cliv2/internal/httpauth/spnego_windows.go deleted file mode 100644 index a938a021b9..0000000000 --- a/cliv2/internal/httpauth/spnego_windows.go +++ /dev/null @@ -1,76 +0,0 @@ -package httpauth - -import ( - "encoding/base64" - "github.com/alexbrainman/sspi/negotiate" - "log" - "net/url" -) - -type WindowsSpnegoProvider struct { - clientContext *negotiate.ClientContext -} - -func SpnegoProviderInstance() SpnegoProvider { - return &WindowsSpnegoProvider{} -} - -func (s *WindowsSpnegoProvider) init(url *url.URL) ([]byte, error) { - hostname := url.Hostname() - token := []byte{} - - spn := "HTTP/" + hostname - - cred, err := negotiate.AcquireCurrentUserCredentials() - if err != nil { - return token, err - } - defer cred.Release() - - secctx, token, err := negotiate.NewClientContext(cred, spn) - if err != nil { - return token, err - } - - s.clientContext = secctx - return token, nil -} - -func (s *WindowsSpnegoProvider) update(responseToken string) ([]byte, bool, error) { - var decodedToken []byte - var newRequesToken []byte - var err error - done := false - - decodedToken, err = base64.StdEncoding.DecodeString(responseToken) - if err != nil { - return newRequesToken, done, err - } - - done, newRequesToken, err = s.clientContext.Update(decodedToken) - - return newRequesToken, done, err -} - -func (s *WindowsSpnegoProvider) GetToken(url *url.URL, responseToken string) (string, bool, error) { - var err error - var token []byte - done := false - - if s.clientContext == nil { - token, err = s.init(url) - } else { - token, done, err = s.update(responseToken) - } - - encodedToken := base64.StdEncoding.EncodeToString(token) - return encodedToken, done, err -} - -func (s *WindowsSpnegoProvider) Close() error { - return s.clientContext.Release() -} - -func (s *WindowsSpnegoProvider) SetLogger(logger *log.Logger) { - //this implementation currently doesn't require a logger -} diff --git a/cliv2/internal/httpauth/test/helper/mock_http_server.go b/cliv2/internal/httpauth/test/helper/mock_http_server.go deleted file mode 100644 index 8370dfb6b2..0000000000 --- a/cliv2/internal/httpauth/test/helper/mock_http_server.go +++ /dev/null @@ -1,54 +0,0 @@ -package helper - -import ( - "fmt" - "net" - "net/http" -) - -type MockServer struct { - Port int - ResponseList []*http.Response - responseIndex int - listener net.Listener -} - -func NewMockServer() *MockServer { - listener, err := net.Listen("tcp", ":0") - if err != nil { - panic(err) - } - - server := MockServer{ResponseList: []*http.Response{}} - server.Port = listener.Addr().(*net.TCPAddr).Port - server.listener = listener - fmt.Println("Using port:", listener.Addr().(*net.TCPAddr).Port) - - return &server -} - -func (m *MockServer) Listen() { - http.Serve(m.listener, m) -} - -func (m *MockServer) ServeHTTP(writer http.ResponseWriter, request *http.Request) { - var response *http.Response - - if m.responseIndex < len(m.ResponseList) { - response = m.ResponseList[m.responseIndex] - m.responseIndex++ - } else { - response = &http.Response{StatusCode: 200} - } - - fmt.Printf("%4d. Request: %v\n", m.responseIndex, request) - fmt.Printf("%4d. Response: %v\n", m.responseIndex, response) - - for k, v := range response.Header { - for i := range v { - writer.Header().Add(k, v[i]) - } - } - - writer.WriteHeader(response.StatusCode) -} diff --git a/cliv2/internal/proxy/proxy.go b/cliv2/internal/proxy/proxy.go index 3c0f98fc9e..8ac4860ef6 100644 --- a/cliv2/internal/proxy/proxy.go +++ b/cliv2/internal/proxy/proxy.go @@ -12,8 +12,8 @@ import ( "os" "github.com/snyk/cli/cliv2/internal/certs" - "github.com/snyk/cli/cliv2/internal/httpauth" "github.com/snyk/cli/cliv2/internal/utils" + "github.com/snyk/go-httpauth/pkg/httpauth" "github.com/elazarl/goproxy" ) diff --git a/cliv2/internal/proxy/proxy_test.go b/cliv2/internal/proxy/proxy_test.go index 4a8ee905ec..fbbad1ca7b 100644 --- a/cliv2/internal/proxy/proxy_test.go +++ b/cliv2/internal/proxy/proxy_test.go @@ -12,8 +12,8 @@ import ( "os" "testing" - "github.com/snyk/cli/cliv2/internal/httpauth" "github.com/snyk/cli/cliv2/internal/proxy" + "github.com/snyk/go-httpauth/pkg/httpauth" "github.com/stretchr/testify/assert" ) diff --git a/cliv2/test/acceptance/proxy_authentication.spec.ts b/cliv2/test/acceptance/proxy_authentication.spec.ts index 49d031c8c4..1753911092 100644 --- a/cliv2/test/acceptance/proxy_authentication.spec.ts +++ b/cliv2/test/acceptance/proxy_authentication.spec.ts @@ -19,14 +19,7 @@ jest.setTimeout(1000 * 60); // Global test configuration const rootDir = path.resolve(path.join(__dirname, '..', '..')); const squidEnvironmentPath = path.resolve( - path.join( - rootDir, - 'internal', - 'httpauth', - 'test', - 'fixtures', - 'squid_environment', - ), + path.join(rootDir, 'test', 'fixtures', 'squid_environment'), ); const dockerComposeFile = path.resolve( path.join(squidEnvironmentPath, 'docker-compose.yml'), diff --git a/cliv2/internal/httpauth/test/fixtures/squid_environment/Dockerfile b/cliv2/test/fixtures/squid_environment/Dockerfile similarity index 100% rename from cliv2/internal/httpauth/test/fixtures/squid_environment/Dockerfile rename to cliv2/test/fixtures/squid_environment/Dockerfile diff --git a/cliv2/internal/httpauth/test/fixtures/squid_environment/docker-compose.yml b/cliv2/test/fixtures/squid_environment/docker-compose.yml similarity index 100% rename from cliv2/internal/httpauth/test/fixtures/squid_environment/docker-compose.yml rename to cliv2/test/fixtures/squid_environment/docker-compose.yml diff --git a/cliv2/internal/httpauth/test/fixtures/squid_environment/scripts/setup.sh b/cliv2/test/fixtures/squid_environment/scripts/setup.sh similarity index 100% rename from cliv2/internal/httpauth/test/fixtures/squid_environment/scripts/setup.sh rename to cliv2/test/fixtures/squid_environment/scripts/setup.sh From a8732a616ac3c85948a7b36ee500d719a7c308f2 Mon Sep 17 00:00:00 2001 From: Yaron Schwimmer Date: Tue, 13 Sep 2022 13:07:23 +0300 Subject: [PATCH 28/55] fix: container python app scan performance issues --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8083196b1f..ccb43fbf03 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,7 +66,7 @@ "semver": "^6.0.0", "snyk-config": "4.0.0", "snyk-cpp-plugin": "2.20.0", - "snyk-docker-plugin": "^5.4.1", + "snyk-docker-plugin": "^5.4.2", "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.22.2", "snyk-module": "3.1.0", @@ -16512,9 +16512,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/snyk-docker-plugin": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.1.tgz", - "integrity": "sha512-x0erNrYCc72ZCj81LL85xibmU763otQACLW8aSUEAsLnSFpoKoE+tnQG5Z9BiEXYbSNXRsll/eS82gzhpHcFKQ==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.2.tgz", + "integrity": "sha512-Rbsrag2PoC4Uz3AjHktgBaL5z22+utmVG2jnWWCysmlAcBeixfxMzlmjL4tFrKRvv5jF71JtVlt6g6jcoXfwQg==", "dependencies": { "@snyk/composer-lockfile-parser": "^1.4.1", "@snyk/dep-graph": "^2.3.0", @@ -32919,9 +32919,9 @@ } }, "snyk-docker-plugin": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.1.tgz", - "integrity": "sha512-x0erNrYCc72ZCj81LL85xibmU763otQACLW8aSUEAsLnSFpoKoE+tnQG5Z9BiEXYbSNXRsll/eS82gzhpHcFKQ==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.2.tgz", + "integrity": "sha512-Rbsrag2PoC4Uz3AjHktgBaL5z22+utmVG2jnWWCysmlAcBeixfxMzlmjL4tFrKRvv5jF71JtVlt6g6jcoXfwQg==", "requires": { "@snyk/composer-lockfile-parser": "^1.4.1", "@snyk/dep-graph": "^2.3.0", diff --git a/package.json b/package.json index cf7ee04958..ba281490e7 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "semver": "^6.0.0", "snyk-config": "4.0.0", "snyk-cpp-plugin": "2.20.0", - "snyk-docker-plugin": "^5.4.1", + "snyk-docker-plugin": "^5.4.2", "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.22.2", "snyk-module": "3.1.0", From 17c7bac2e9f6096773d0936b9b2d82391955103b Mon Sep 17 00:00:00 2001 From: Francesco Mari Date: Tue, 13 Sep 2022 11:25:49 +0200 Subject: [PATCH 29/55] feat: share results with the Cloud API --- src/cli/commands/test/iac/v2/assert-iac-options.ts | 4 ++++ .../v2/local-cache/policy-engine/constants/utils.ts | 13 +++++++------ src/lib/iac/test/v2/scan/index.ts | 8 +++++++- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/cli/commands/test/iac/v2/assert-iac-options.ts b/src/cli/commands/test/iac/v2/assert-iac-options.ts index 7a03fc3a10..951a4f82c7 100644 --- a/src/cli/commands/test/iac/v2/assert-iac-options.ts +++ b/src/cli/commands/test/iac/v2/assert-iac-options.ts @@ -33,6 +33,10 @@ const keys: (keyof IaCTestFlags)[] = [ // PolicyOptions 'ignore-policy', 'policy-path', + 'report', + 'remote-repo-url', + 'target-name', + 'target-reference', ]; const allowed = new Set(keys); diff --git a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts index 6cc1adeb34..f88c777c99 100644 --- a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts +++ b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts @@ -1,11 +1,12 @@ import * as os from 'os'; -const policyEngineChecksums = `1ab888458215d8ba45452117854adb95060d9dac45f4b602e2e34f500b7b8a3a snyk-iac-test_0.30.1_Linux_arm64 -85e181989cde63797095107c38772edb4cba75a8becd82aad9c609b4c273789b snyk-iac-test_0.30.1_Windows_arm64.exe -8e4bb3f55d6332706485f278d194f09ef08f46db5516b1008db9c152c636ae24 snyk-iac-test_0.30.1_Windows_x86_64.exe -ba478316de02fd69de4463edca221550d5f4eb962e514220b0a9d9a014d18128 snyk-iac-test_0.30.1_Darwin_arm64 -f218a8e8cc25024f7936947c091e9c9ad34c33178cd6558bdda906fc47c1a598 snyk-iac-test_0.30.1_Darwin_x86_64 -ff23fe190e2392ed4b42ee231171806c300bfe2b9983353497c9f1a195c5c499 snyk-iac-test_0.30.1_Linux_x86_64 +const policyEngineChecksums = ` +16211f1b806a85127cad2f1165e39a679a82c6c3d0d6a0bc4fde196710280b73 snyk-iac-test_0.31.2_Linux_x86_64 +931a8eb829c912251ae1d47c7b729148dca2bd3c60a4c8b564f614aeeee9d7c9 snyk-iac-test_0.31.2_Darwin_x86_64 +9536c5b4b4bf6fef94dd110033311b4447857c43bb07d64f5d2bc498cb53366b snyk-iac-test_0.31.2_Windows_arm64.exe +cf24c3b562f5c4282c029510cf679cabb5fa2a96bbf207cdd57f42e960173fb4 snyk-iac-test_0.31.2_Darwin_arm64 +d3bc0efa5e7eec34e9cd2f226e3686329e4a4f371e532851e4d10226e250505d snyk-iac-test_0.31.2_Linux_arm64 +fcebb81c0745d8636d55ac9aa4582acbc38d93a496970d3069c19ab278b5ebb6 snyk-iac-test_0.31.2_Windows_x86_64.exe `; export const policyEngineVersion = getPolicyEngineVersion(); diff --git a/src/lib/iac/test/v2/scan/index.ts b/src/lib/iac/test/v2/scan/index.ts index 1b641657b4..5c32d58f38 100644 --- a/src/lib/iac/test/v2/scan/index.ts +++ b/src/lib/iac/test/v2/scan/index.ts @@ -174,7 +174,7 @@ function createTemporaryFiles( const configData = JSON.stringify({ org: options.orgSettings.meta.org, orgPublicId: options.orgSettings.meta.orgPublicId, - apiUrl: config.API, + apiUrl: getApiUrl(), apiAuth: getAuthHeader(), allowAnalytics: allowAnalytics(), policy: options.policy, @@ -198,6 +198,12 @@ function deleteTemporaryFiles(tempDirPath: string) { } } +function getApiUrl() { + const apiUrl = new URL(config.API_REST_URL); + apiUrl.pathname = ''; + return apiUrl.toString(); +} + class ScanError extends CustomError { constructor(message: string) { super(message); From 3f829711918dead4f1f54ff13e14fb7bff316128 Mon Sep 17 00:00:00 2001 From: Francesco Mari Date: Wed, 14 Sep 2022 11:40:38 +0200 Subject: [PATCH 30/55] feat: add support for an HTTP proxy when using snyk-iac-test --- src/cli/commands/test/iac/v2/index.ts | 2 ++ src/lib/iac/test/v2/scan/index.ts | 4 ++++ src/lib/iac/test/v2/types.ts | 1 + 3 files changed, 7 insertions(+) diff --git a/src/cli/commands/test/iac/v2/index.ts b/src/cli/commands/test/iac/v2/index.ts index c065a071e5..23a245b1f3 100644 --- a/src/cli/commands/test/iac/v2/index.ts +++ b/src/cli/commands/test/iac/v2/index.ts @@ -61,6 +61,7 @@ async function prepareTestConfig( const scan = options.scan ?? 'resource-changes'; const varFile = options['var-file']; const cloudContext = getFlag(options, 'cloud-context'); + const insecure = options.insecure; return { paths, @@ -80,6 +81,7 @@ async function prepareTestConfig( varFile, depthDetection, cloudContext, + insecure, }; } diff --git a/src/lib/iac/test/v2/scan/index.ts b/src/lib/iac/test/v2/scan/index.ts index 5c32d58f38..e98085dff2 100644 --- a/src/lib/iac/test/v2/scan/index.ts +++ b/src/lib/iac/test/v2/scan/index.ts @@ -160,6 +160,10 @@ function processFlags( flags.push('-cloud-context', options.cloudContext); } + if (options.insecure) { + flags.push('-http-tls-skip-verify'); + } + return flags; } diff --git a/src/lib/iac/test/v2/types.ts b/src/lib/iac/test/v2/types.ts index 769aa8edac..969caae0e9 100644 --- a/src/lib/iac/test/v2/types.ts +++ b/src/lib/iac/test/v2/types.ts @@ -20,4 +20,5 @@ export interface TestConfig { varFile?: string; depthDetection?: number; cloudContext?: string; + insecure?: boolean; } From c1e289d4af19be1fd8c56a9f782b47eb4cebd836 Mon Sep 17 00:00:00 2001 From: Ilianna Papastefanou Date: Wed, 14 Sep 2022 11:42:07 +0100 Subject: [PATCH 31/55] fix: iac test result undefined snyk iac test scan would fail when trying to access snykIacTestScanResult?.scanAnalytics.supressedResults, in the case of snykIacTestScanResult being undefined. This is because the whole snykIacTestScanResult?.scanAnalytics would evaluate to undefine and suppressedResults would fail to read an undefined value. Added a "?" operator to scanAnalytics to fix this error. --- src/lib/formatters/iac-output/text/formatters.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/formatters/iac-output/text/formatters.ts b/src/lib/formatters/iac-output/text/formatters.ts index 698132d9be..b20b8995d8 100644 --- a/src/lib/formatters/iac-output/text/formatters.ts +++ b/src/lib/formatters/iac-output/text/formatters.ts @@ -111,7 +111,7 @@ export function formatSnykIacTestTestData( let contextSuppressedIssueCount: number | undefined; const suppressedResults = - snykIacTestScanResult?.scanAnalytics.suppressedResults; + snykIacTestScanResult?.scanAnalytics?.suppressedResults; if (suppressedResults) { contextSuppressedIssueCount = Object.values(suppressedResults).reduce( function(count, resourcesForRuleId) { From 4db2a46232ef43afee23f4c364c9fb4e9849a93f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramon=20R=C3=BCttimann?= Date: Wed, 14 Sep 2022 15:12:01 +0200 Subject: [PATCH 32/55] fix: update snyk-docker-plugin to fix CGo binaries issue See [snyk-docker-plugin #456](https://github.com/snyk/snyk-docker-plugin/pull/456) for more info. --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 63d42f3ecf..5261c42041 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,7 +66,7 @@ "semver": "^6.0.0", "snyk-config": "4.0.0", "snyk-cpp-plugin": "2.20.0", - "snyk-docker-plugin": "^5.4.2", + "snyk-docker-plugin": "^5.4.3", "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.22.2", "snyk-module": "3.1.0", @@ -16570,9 +16570,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/snyk-docker-plugin": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.2.tgz", - "integrity": "sha512-Rbsrag2PoC4Uz3AjHktgBaL5z22+utmVG2jnWWCysmlAcBeixfxMzlmjL4tFrKRvv5jF71JtVlt6g6jcoXfwQg==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.3.tgz", + "integrity": "sha512-cv1wVei4psebrMAYyCXkrL5cYpVbPvraX5JlxDjpTJetV4C8NoQHjKH8ORXhShvkczR5ca68TAbbzK9RJ7azug==", "dependencies": { "@snyk/composer-lockfile-parser": "^1.4.1", "@snyk/dep-graph": "^2.3.0", @@ -32961,9 +32961,9 @@ } }, "snyk-docker-plugin": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.2.tgz", - "integrity": "sha512-Rbsrag2PoC4Uz3AjHktgBaL5z22+utmVG2jnWWCysmlAcBeixfxMzlmjL4tFrKRvv5jF71JtVlt6g6jcoXfwQg==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.3.tgz", + "integrity": "sha512-cv1wVei4psebrMAYyCXkrL5cYpVbPvraX5JlxDjpTJetV4C8NoQHjKH8ORXhShvkczR5ca68TAbbzK9RJ7azug==", "requires": { "@snyk/composer-lockfile-parser": "^1.4.1", "@snyk/dep-graph": "^2.3.0", diff --git a/package.json b/package.json index fdf02595c6..a64bd28f7f 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "semver": "^6.0.0", "snyk-config": "4.0.0", "snyk-cpp-plugin": "2.20.0", - "snyk-docker-plugin": "^5.4.2", + "snyk-docker-plugin": "^5.4.3", "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.22.2", "snyk-module": "3.1.0", From 394205114fb2759f870d5f60f546711fb6f758bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Scha=CC=88fer?= <101886095+PeterSchafer@users.noreply.github.com> Date: Tue, 13 Sep 2022 18:45:59 +0200 Subject: [PATCH 33/55] chore: forward errors further and derive exit code later MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit in preparation of beng able to include errors in analytics. Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: add initial analytics implementation, not yet working Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: Adding next increment of analytics Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: fix unit test Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: implement sanitization of output data Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: add missing length check Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: adapt analytics output format Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: introduce global configuration based on viper * cliv2: make getFullVersion() static Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: fix prepare_licenses after adding new dependencies Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: Extend Analytics and Configuration * Analytics to include additional data + support disabling it + use proper authorization token * Configuration support bool and default values * In general moved constants away from cliv2 package to constants to enable linear inclusion Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: fix tests and add missing alternative key for token Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: improve configuration tests Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> fix: test by printing to stderr Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> fix: test by removing logging in configuration Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: set correct value for standalone Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: fix and extend tests to handle additional analytics Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> chore: fix tests to handle additional analytics Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> --- cliv2/.snyk | 127 +++++ cliv2/cmd/cliv2/main.go | 68 ++- cliv2/go.mod | 18 +- cliv2/go.sum | 441 +++++++++++++++++- cliv2/internal/analytics/analytics.go | 249 ++++++++++ cliv2/internal/analytics/analytics_test.go | 115 +++++ cliv2/internal/cliv2/cliv2.go | 138 +++--- cliv2/internal/cliv2/cliv2_test.go | 23 +- cliv2/internal/configuration/configuration.go | 150 ++++++ .../configuration/configuration_test.go | 97 ++++ cliv2/internal/constants/constants.go | 17 + cliv2/internal/utils/api_tokens.go | 22 + cliv2/scripts/prepare_licenses.sh | 2 +- test/jest/acceptance/analytics.spec.ts | 63 +++ .../protect-upgrade-notification.spec.ts | 21 + 15 files changed, 1451 insertions(+), 100 deletions(-) create mode 100644 cliv2/.snyk create mode 100644 cliv2/internal/analytics/analytics.go create mode 100644 cliv2/internal/analytics/analytics_test.go create mode 100644 cliv2/internal/configuration/configuration.go create mode 100644 cliv2/internal/configuration/configuration_test.go create mode 100644 cliv2/internal/constants/constants.go create mode 100644 cliv2/internal/utils/api_tokens.go diff --git a/cliv2/.snyk b/cliv2/.snyk new file mode 100644 index 0000000000..c90901de1a --- /dev/null +++ b/cliv2/.snyk @@ -0,0 +1,127 @@ +# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. +version: v1.25.0 +# ignores vulnerabilities until expiry date; change duration by modifying expiry date +ignore: + 'snyk:lic:golang:github.com:hashicorp:hcl:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:hashicorp:go-uuid:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:hashicorp:serf:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:hashicorp:errwrap:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:hashicorp:logutils:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:hashicorp:consul:sdk:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:hashicorp:golang-lru:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:hashicorp:memberlist:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:hashicorp:consul:api:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:hashicorp:go-sockaddr:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:hashicorp:go-cleanhttp:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:hashicorp:go-rootcerts:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:hashicorp:go-multierror:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:hashicorp:go-retryablehttp:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:hashicorp:go-immutable-radix:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + 'snyk:lic:golang:github.com:mitchellh:cli:MPL-2.0': + - '*': + reason: >- + see + https://www.notion.so/snyk/MPL2-0-Use-Cases-4fe1a7a193354353a3603153e92a0a6d + expires: 2033-09-13T17:00:11.886Z + created: 2022-09-13T17:00:11.897Z + SNYK-GOLANG-GITHUBCOMGOGOPROTOBUFPLUGINUNMARSHAL-1058921: + - '*': + reason: Affected functionality is not used. + expires: 2023-09-14T08:42:41.894Z + created: 2022-09-14T08:42:41.931Z + SNYK-GOLANG-GITHUBCOMPROMETHEUSCLIENTGOLANGPROMETHEUSPROMHTTP-2401819: + - '*': + reason: Affected functionality is not used. + expires: 2023-09-14T08:43:11.340Z + created: 2022-09-14T08:43:11.370Z +patch: {} diff --git a/cliv2/cmd/cliv2/main.go b/cliv2/cmd/cliv2/main.go index a4bc909723..a4229dbd5f 100644 --- a/cliv2/cmd/cliv2/main.go +++ b/cliv2/cmd/cliv2/main.go @@ -4,9 +4,13 @@ import ( "fmt" "io/ioutil" "log" + "net/http" "os" + "github.com/snyk/cli/cliv2/internal/analytics" "github.com/snyk/cli/cliv2/internal/cliv2" + "github.com/snyk/cli/cliv2/internal/configuration" + "github.com/snyk/cli/cliv2/internal/constants" "github.com/snyk/cli/cliv2/internal/proxy" "github.com/snyk/cli/cliv2/internal/utils" "github.com/snyk/go-httpauth/pkg/httpauth" @@ -62,8 +66,44 @@ func main() { os.Exit(errorCode) } +func initAnalytics(args []string, config configuration.Configuration) *analytics.Analytics { + + headerFunc := func() http.Header { + h := http.Header{} + + authHeader := utils.GetAuthHeader(config) + if len(authHeader) > 0 { + h.Add("Authorization", authHeader) + } + + h.Add("x-snyk-cli-version", cliv2.GetFullVersion()) + return h + } + + cliAnalytics := analytics.New() + cliAnalytics.SetVersion(cliv2.GetFullVersion()) + cliAnalytics.SetCmdArguments(args) + cliAnalytics.SetIntegration(config.GetString(configuration.INTEGRATION_NAME), config.GetString(configuration.INTEGRATION_VERSION)) + cliAnalytics.SetApiUrl(config.GetString(configuration.API_URL)) + cliAnalytics.AddHeader(headerFunc) + + mappedArguments := utils.ToKeyValueMap(args, "=") + if org, ok := mappedArguments["--org"]; ok { + cliAnalytics.SetOrg(org) + } + + return cliAnalytics +} + func MainWithErrorCode(envVariables EnvironmentVariables, args []string) int { var err error + config := configuration.New() + + cliAnalytics := initAnalytics(args, config) + if config.GetBool(configuration.ANALYTICS_DISABLED) == false { + defer cliAnalytics.Send() + } + debugLogger := getDebugLogger(args) debugLogger.Println("debug: true") @@ -75,39 +115,47 @@ func MainWithErrorCode(envVariables EnvironmentVariables, args []string) int { if err != nil { fmt.Println("Failed to determine cache directory!") fmt.Println(err) - return cliv2.SNYK_EXIT_CODE_ERROR + return constants.SNYK_EXIT_CODE_ERROR } } // init cli object var cli *cliv2.CLI - cli = cliv2.NewCLIv2(envVariables.CacheDirectory, debugLogger) - if cli == nil { - return cliv2.SNYK_EXIT_CODE_ERROR + cli, err = cliv2.NewCLIv2(envVariables.CacheDirectory, debugLogger) + if err != nil { + cliAnalytics.AddError(err) + return constants.SNYK_EXIT_CODE_ERROR } // init proxy object - wrapperProxy, err := proxy.NewWrapperProxy(envVariables.Insecure, envVariables.CacheDirectory, cli.GetFullVersion(), debugLogger) + wrapperProxy, err := proxy.NewWrapperProxy(envVariables.Insecure, envVariables.CacheDirectory, cliv2.GetFullVersion(), debugLogger) + defer wrapperProxy.Close() if err != nil { fmt.Println("Failed to create proxy") fmt.Println(err) - return cliv2.SNYK_EXIT_CODE_ERROR + cliAnalytics.AddError(err) + return constants.SNYK_EXIT_CODE_ERROR } wrapperProxy.SetUpstreamProxyAuthentication(envVariables.ProxyAuthenticationMechanism) + http.DefaultTransport = wrapperProxy.Transport() port, err := wrapperProxy.Start() if err != nil { fmt.Println("Failed to start the proxy") fmt.Println(err) - return cliv2.SNYK_EXIT_CODE_ERROR + cliAnalytics.AddError(err) + return constants.SNYK_EXIT_CODE_ERROR } // run the cli - exitCode := cli.Execute(port, wrapperProxy.CertificateLocation, args) + err = cli.Execute(port, wrapperProxy.CertificateLocation, args) + if err != nil { + cliAnalytics.AddError(err) + } + + exitCode := cli.DeriveExitCode(err) - debugLogger.Println("in main, cliv1 is done") - wrapperProxy.Close() debugLogger.Printf("Exiting with %d\n", exitCode) return exitCode diff --git a/cliv2/go.mod b/cliv2/go.mod index 6b22e3414f..548439b1b8 100644 --- a/cliv2/go.mod +++ b/cliv2/go.mod @@ -4,25 +4,39 @@ go 1.18 require ( github.com/elazarl/goproxy v0.0.0-20220328115640-894aeddb713e + github.com/hashicorp/go-uuid v1.0.3 github.com/snyk/go-httpauth v0.0.0-20220912133144-d51219ca664d + github.com/spf13/viper v1.13.0 github.com/stretchr/testify v1.8.0 ) require ( github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/golang/mock v1.6.0 // indirect - github.com/hashicorp/go-uuid v1.0.3 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/gofork v1.7.6 // indirect github.com/jcmturner/goidentity/v6 v6.0.1 // indirect github.com/jcmturner/gokrb5/v8 v8.4.3 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect - github.com/kr/text v0.2.0 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/spf13/afero v1.8.2 // indirect + github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.4.1 // indirect golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 // indirect golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c // indirect + golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 // indirect golang.org/x/text v0.3.7 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/cliv2/go.sum b/cliv2/go.sum index 5bf1a0265e..d8458b29b9 100644 --- a/cliv2/go.sum +++ b/cliv2/go.sum @@ -1,6 +1,53 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -8,8 +55,75 @@ github.com/elazarl/goproxy v0.0.0-20220328115640-894aeddb713e h1:99KFda6F/mw8xSf github.com/elazarl/goproxy v0.0.0-20220328115640-894aeddb713e/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= @@ -17,6 +131,12 @@ github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= @@ -29,62 +149,379 @@ github.com/jcmturner/gokrb5/v8 v8.4.3 h1:iTonLeSJOn7MVUtyMT+arAn5AKAPrkilzhGw8wE github.com/jcmturner/gokrb5/v8 v8.4.3/go.mod h1:dqRwJGXznQrzw6cWmyo6kH+E7jksEQG/CyVWsJEsJO0= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/snyk/go-httpauth v0.0.0-20220912133144-d51219ca664d h1:dT2rfoDxGDWeplsnXWajWZcZ7zo8R6Hif3jufvkXcUE= github.com/snyk/go-httpauth v0.0.0-20220912133144-d51219ca664d/go.mod h1:v6t6wKizOcHXT3p4qKn6Bda7yNIjCQ54Xyl31NjgXkY= +github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= +github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8 h1:GIAS/yBem/gq2MUqgNIzUHW7cJMmx3TGZOrnyYaNQ6c= golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c h1:JVAXQ10yGGVbSyoer5VILysz6YKjdNT2bsvlayjqhes= golang.org/x/net v0.0.0-20220822230855-b0a4917ee28c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 h1:Sx/u41w+OwrInGdEckYmEuU5gHoGSL4QbDz3S9s6j4U= +golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/cliv2/internal/analytics/analytics.go b/cliv2/internal/analytics/analytics.go new file mode 100644 index 0000000000..4f649e1e1e --- /dev/null +++ b/cliv2/internal/analytics/analytics.go @@ -0,0 +1,249 @@ +package analytics + +import ( + "bytes" + "crypto/sha1" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "os" + "regexp" + "runtime" + "time" + + "github.com/hashicorp/go-uuid" + "github.com/snyk/cli/cliv2/internal/utils" +) + +type Analytics struct { + headerFunc func() http.Header + apiUrl string + + org string + version string + created time.Time + args []string + errorList []error + integrationName string + integrationVersion string +} + +type metadataOutput struct { + ErrorMessage string `json:"error-message,omitempty"` + ErrorCode string `json:"error-code,omitempty"` +} + +type metricsOutput struct { +} + +type analyticsOutput struct { + Command string `json:"command"` + Args []string `json:"args"` + OsPlatform string `json:"osPlatform"` + OsArch string `json:"osArch"` + Os string `json:"os"` + OsRelease string `json:"osRelease"` + Metadata metadataOutput `json:"metadata"` + Id string `json:"id"` + Version string `json:"version"` + DurationMs int64 `json:"durationMs"` + Metrics metricsOutput `json:"metrics"` + Ci bool `json:"ci"` + IntegrationName string `json:"integrationName"` + IntegrationVersion string `json:"integrationVersion"` + IntegrationEnvironment string `json:"integrationEnvironment"` + IntegrationEnvironmentVersion string `json:"integrationEnvironmentVersion"` + NodeVersion string `json:"nodeVersion"` + Standalone bool `json:"standalone"` +} + +type dataOutput struct { + Data analyticsOutput `json:"data"` +} + +var ( + ciEnvironments []string = []string{ + "SNYK_CI", + "CI", + "CONTINUOUS_INTEGRATION", + "BUILD_ID", + "BUILD_NUMBER", + "TEAMCITY_VERSION", + "TRAVIS", + "CIRCLECI", + "JENKINS_URL", + "HUDSON_URL", + "bamboo.buildKey", + "PHPCI", + "GOCD_SERVER_HOST", + "BUILDKITE", + "TF_BUILD", + "SYSTEM_TEAMFOUNDATIONSERVERURI", // for Azure DevOps Pipelines + } + + sensitiveFieldNames []string = []string{ + "tfc-token", + "azurerm-account-key", + "fetch-tfstate-headers", + "username", + "password", + } +) + +const ( + sanitize_replacement_string string = "REDACTED" + api_endpoint = "/v1/analytics/cli" +) + +func New() *Analytics { + a := &Analytics{} + a.headerFunc = func() http.Header { return http.Header{} } + a.created = time.Now() + return a +} + +func (a *Analytics) SetCmdArguments(args []string) { + a.args = args +} + +func (a *Analytics) SetOrg(org string) { + a.org = org +} + +func (a *Analytics) SetVersion(version string) { + a.version = version +} + +func (a *Analytics) SetApiUrl(apiUrl string) { + a.apiUrl = apiUrl +} + +func (a *Analytics) SetIntegration(name string, version string) { + a.integrationName = name + a.integrationVersion = version +} + +func (a *Analytics) AddError(err error) { + a.errorList = append(a.errorList, err) +} + +func (a *Analytics) AddHeader(headerFunc func() http.Header) { + a.headerFunc = headerFunc +} + +func (a *Analytics) IsCiEnvironment() bool { + result := false + + envMap := utils.ToKeyValueMap(os.Environ(), "=") + for i := range ciEnvironments { + if _, ok := envMap[ciEnvironments[i]]; ok { + result = true + break + } + } + + return result +} + +func (a *Analytics) GetOutputData() *analyticsOutput { + output := &analyticsOutput{} + + errorCount := len(a.errorList) + if errorCount > 0 { + lastError := a.errorList[errorCount-1] + output.Metadata = metadataOutput{ + ErrorMessage: lastError.Error(), + } + } + + // deepcode ignore InsecureHash: It is just being used to generate an id, without any security concerns + shasum := sha1.New() + uuid, _ := uuid.GenerateUUID() + io.WriteString(shasum, uuid) + output.Id = fmt.Sprintf("%x", shasum.Sum(nil)) + + output.Args = a.args + + if len(a.args) > 0 { + output.Command = a.args[0] + } + + output.OsPlatform = runtime.GOOS + output.OsArch = runtime.GOARCH + output.Version = a.version + output.NodeVersion = runtime.Version() + output.Ci = a.IsCiEnvironment() + output.IntegrationName = a.integrationName + output.IntegrationVersion = a.integrationVersion + output.DurationMs = int64(time.Since(a.created).Milliseconds()) + output.Standalone = true // standalone means binary deployment, which is always true for go applications. + + return output +} + +func (a *Analytics) GetRequest() (*http.Request, error) { + output := a.GetOutputData() + + outputJson, err := json.Marshal(dataOutput{Data: *output}) + if err != nil { + return nil, err + } + + outputJson, err = SanitizeValuesByKey(sensitiveFieldNames, sanitize_replacement_string, outputJson) + if err != nil { + return nil, err + } + + analyticsUrl, _ := url.Parse(a.apiUrl + api_endpoint) + if len(a.org) > 0 { + query := url.Values{} + query.Add("org", a.org) + analyticsUrl.RawQuery = query.Encode() + } + + body := bytes.NewReader(outputJson) + request, err := http.NewRequest(http.MethodPost, analyticsUrl.String(), body) + if err != nil { + return nil, err + } + + if a.headerFunc != nil { + request.Header = a.headerFunc() + } + + request.Header.Set("Content-Type", "application/json; charset=utf-8") + + return request, err +} + +func (a *Analytics) Send() (*http.Response, error) { + request, err := a.GetRequest() + if err != nil { + return nil, err + } + + client := http.Client{} + response, err := client.Do(request) + + return response, err +} + +// This method sanitizes the given content by searching for key-value mappings. It thereby replaces all keys defined in keysToFilter by the replacement string +// Supported patterns are: +// * key : "value" +// * key = "value" +// * key = value +func SanitizeValuesByKey(keysToFilter []string, replacementValue string, content []byte) ([]byte, error) { + for i := range keysToFilter { + filter := keysToFilter[i] + r, err := regexp.Compile("(?i)([\"']?\\w*" + filter + "\\w*\"?)(((\\s?[:]\\s?[\"'])[^\n\"']*([\"']))|((\\s?[=]\\s?[\"']?)[^\n\"']*([\"']?)))") + if err != nil { + return nil, err + } + + content = r.ReplaceAll(content, []byte("${1}${4}${7}"+replacementValue+"${5}${8}")) + } + return content, nil +} diff --git a/cliv2/internal/analytics/analytics_test.go b/cliv2/internal/analytics/analytics_test.go new file mode 100644 index 0000000000..a746cf3c83 --- /dev/null +++ b/cliv2/internal/analytics/analytics_test.go @@ -0,0 +1,115 @@ +package analytics + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_Basic(t *testing.T) { + os.Setenv("CIRCLECI", "true") + + api := "http://myapi.com" + org := "MyOrgAs" + h := http.Header{} + h.Add("Authorization", "token 4ac534fac6fd6790b7") + + // prepare test data + args := []string{"test", "--flag", "b=1"} + for i := range sensitiveFieldNames { + args = append(args, fmt.Sprintf("%s=%s", sensitiveFieldNames[i], "secretvalue")) + } + + analytics := New() + analytics.SetCmdArguments(args) + analytics.AddError(fmt.Errorf("Something went terrible wrong.")) + analytics.SetVersion("1234567") + analytics.SetOrg(org) + analytics.SetApiUrl(api) + analytics.SetIntegration("Jenkins", "1.2.3.4") + analytics.AddHeader(func() http.Header { + return h.Clone() + }) + + // invoke method under test + request, err := analytics.GetRequest() + + // compare results + assert.Nil(t, err) + assert.NotNil(t, request) + assert.True(t, analytics.IsCiEnvironment()) + + expectedAuthHeader, _ := h["Authorization"] + actualAuthHeader, _ := request.Header["Authorization"] + assert.Equal(t, expectedAuthHeader, actualAuthHeader) + + requestUrl := request.URL.String() + assert.True(t, strings.Contains(requestUrl, api)) + assert.True(t, strings.Contains(requestUrl, org)) + + body, err := io.ReadAll(request.Body) + assert.Nil(t, err) + assert.Equal(t, len(sensitiveFieldNames), strings.Count(string(body), sanitize_replacement_string), "Not all sensitive values have been replaced!") + + fmt.Println("Request Url: " + requestUrl) + fmt.Println("Request Body: " + string(body)) +} + +func Test_SanitizeValuesByKey(t *testing.T) { + secretValues := []string{"mypassword", "123", "#er+aVnqOjnyTtzn-snyk", "Patch", "DogsRule"} + expectedNumberOfRedacted := len(secretValues) + + type sanTest struct { + Password string `json:"password"` + JenkinsPassword string + PrivateKeySecret string + SecretNumber int + TotallyPublicValue bool + Args []string + } + + inputStruct := sanTest{ + Password: secretValues[2], + JenkinsPassword: secretValues[0], + PrivateKeySecret: secretValues[1], + SecretNumber: 987654, + TotallyPublicValue: false, + Args: []string{"--username=" + secretValues[3], "password=" + secretValues[4], "something=else"}, + } + + // test input + filter := []string{"password", "Secret", "username"} + input, _ := json.Marshal(inputStruct) + replacement := "REDACTED" + + fmt.Println("Before: " + string(input)) + + // invoke method under test + output, err := SanitizeValuesByKey(filter, replacement, input) + + fmt.Println("After: " + string(output)) + + assert.Nil(t, err, "Failed to santize!") + actualNumberOfRedacted := strings.Count(string(output), replacement) + assert.Equal(t, expectedNumberOfRedacted, actualNumberOfRedacted) + + var outputStruct sanTest + err = json.Unmarshal(output, &outputStruct) + assert.Nil(t, err, "Failed to decode json object!") + + // count how often the known secrets are being found in the input and the output + secretsCountAfter := 0 + secretsCountBefore := 0 + for i := range secretValues { + secretsCountBefore += strings.Count(string(input), secretValues[i]) + secretsCountAfter += strings.Count(string(output), secretValues[i]) + } + assert.Equal(t, expectedNumberOfRedacted, secretsCountBefore) + assert.Equal(t, 0, secretsCountAfter) +} diff --git a/cliv2/internal/cliv2/cliv2.go b/cliv2/internal/cliv2/cliv2.go index dd9a6e4bb6..a7bb6871a3 100644 --- a/cliv2/internal/cliv2/cliv2.go +++ b/cliv2/internal/cliv2/cliv2.go @@ -11,6 +11,7 @@ import ( "os/exec" "strings" + "github.com/snyk/cli/cliv2/internal/constants" "github.com/snyk/cli/cliv2/internal/embedded" "github.com/snyk/cli/cliv2/internal/embedded/cliv1" "github.com/snyk/cli/cliv2/internal/utils" @@ -22,29 +23,12 @@ type CLI struct { DebugLogger *log.Logger CacheDirectory string v1BinaryLocation string - v1Version string - v2Version string } type EnvironmentWarning struct { message string } -const SNYK_EXIT_CODE_OK = 0 -const SNYK_EXIT_CODE_ERROR = 2 -const SNYK_INTEGRATION_NAME = "CLI_V1_PLUGIN" -const SNYK_INTEGRATION_NAME_ENV = "SNYK_INTEGRATION_NAME" -const SNYK_INTEGRATION_VERSION_ENV = "SNYK_INTEGRATION_VERSION" -const SNYK_HTTPS_PROXY_ENV = "HTTPS_PROXY" -const SNYK_HTTP_PROXY_ENV = "HTTP_PROXY" -const SNYK_HTTP_NO_PROXY_ENV = "NO_PROXY" -const SNYK_NPM_PROXY_ENV = "NPM_CONFIG_PROXY" -const SNYK_NPM_HTTPS_PROXY_ENV = "NPM_CONFIG_HTTPS_PROXY" -const SNYK_NPM_HTTP_PROXY_ENV = "NPM_CONFIG_HTTP_PROXY" -const SNYK_NPM_NO_PROXY_ENV = "NPM_CONFIG_NO_PROXY" -const SNYK_NPM_ALL_PROXY = "ALL_PROXY" -const SNYK_CA_CERTIFICATE_LOCATION_ENV = "NODE_EXTRA_CA_CERTS" - const ( V1_DEFAULT Handler = iota V2_VERSION Handler = iota @@ -52,31 +36,29 @@ const ( ) //go:embed cliv2.version -var SNYK_CLIV2_VERSION_PART string +var version_prefix string -func NewCLIv2(cacheDirectory string, debugLogger *log.Logger) *CLI { +func NewCLIv2(cacheDirectory string, debugLogger *log.Logger) (*CLI, error) { v1BinaryLocation, err := cliv1.GetFullCLIV1TargetPath(cacheDirectory) if err != nil { fmt.Println(err) - return nil + return nil, err } cli := CLI{ DebugLogger: debugLogger, CacheDirectory: cacheDirectory, - v1Version: cliv1.CLIV1Version(), - v2Version: strings.TrimSpace(SNYK_CLIV2_VERSION_PART), v1BinaryLocation: v1BinaryLocation, } err = cli.ExtractV1Binary() if err != nil { fmt.Println(err) - return nil + return nil, err } - return &cli + return &cli, nil } func (c *CLI) ExtractV1Binary() error { @@ -109,16 +91,19 @@ func (c *CLI) ExtractV1Binary() error { return nil } -func (c *CLI) GetFullVersion() string { - if len(c.v2Version) > 0 { - return c.v2Version + "." + c.v1Version +func GetFullVersion() string { + v1Version := cliv1.CLIV1Version() + v2Version := strings.TrimSpace(version_prefix) + + if len(v2Version) > 0 { + return v2Version + "." + v1Version } else { - return c.v1Version + return v1Version } } func (c *CLI) GetIntegrationName() string { - return SNYK_INTEGRATION_NAME + return constants.SNYK_INTEGRATION_NAME } func (c *CLI) GetBinaryLocation() string { @@ -126,24 +111,23 @@ func (c *CLI) GetBinaryLocation() string { } func (c *CLI) printVersion() { - fmt.Println(c.GetFullVersion()) + fmt.Println(GetFullVersion()) } -func (c *CLI) commandVersion(passthroughArgs []string) int { +func (c *CLI) commandVersion(passthroughArgs []string) error { if utils.Contains(passthroughArgs, "--json-file-output") { - fmt.Println("The following option combination is not currently supported: version + json-file-output") - return SNYK_EXIT_CODE_ERROR + return fmt.Errorf("The following option combination is not currently supported: version + json-file-output") } else { c.printVersion() - return SNYK_EXIT_CODE_OK + return nil } } -func (c *CLI) commandAbout(wrapperProxyPort int, fullPathToCert string, passthroughArgs []string) int { +func (c *CLI) commandAbout(wrapperProxyPort int, fullPathToCert string, passthroughArgs []string) error { - returnCode := c.executeV1Default(wrapperProxyPort, fullPathToCert, passthroughArgs) - if returnCode != SNYK_EXIT_CODE_OK { - return returnCode + err := c.executeV1Default(wrapperProxyPort, fullPathToCert, passthroughArgs) + if err != nil { + return err } separator := "\n+-+-+-+-+-+-+\n\n" @@ -167,7 +151,7 @@ func (c *CLI) commandAbout(wrapperProxyPort int, fullPathToCert string, passthro } } - return SNYK_EXIT_CODE_OK + return nil } func determineHandler(passthroughArgs []string) Handler { @@ -189,29 +173,29 @@ func PrepareV1EnvironmentVariables(input []string, integrationName string, integ inputAsMap := utils.ToKeyValueMap(input, "=") result = input - _, integrationNameExists := inputAsMap[SNYK_INTEGRATION_NAME_ENV] - _, integrationVersionExists := inputAsMap[SNYK_INTEGRATION_VERSION_ENV] + _, integrationNameExists := inputAsMap[constants.SNYK_INTEGRATION_NAME_ENV] + _, integrationVersionExists := inputAsMap[constants.SNYK_INTEGRATION_VERSION_ENV] if !integrationNameExists && !integrationVersionExists { - inputAsMap[SNYK_INTEGRATION_NAME_ENV] = integrationName - inputAsMap[SNYK_INTEGRATION_VERSION_ENV] = integrationVersion + inputAsMap[constants.SNYK_INTEGRATION_NAME_ENV] = integrationName + inputAsMap[constants.SNYK_INTEGRATION_VERSION_ENV] = integrationVersion } else if !(integrationNameExists && integrationVersionExists) { - err = EnvironmentWarning{message: fmt.Sprintf("Partially defined environment, please ensure to provide both %s and %s together!", SNYK_INTEGRATION_NAME_ENV, SNYK_INTEGRATION_VERSION_ENV)} + err = EnvironmentWarning{message: fmt.Sprintf("Partially defined environment, please ensure to provide both %s and %s together!", constants.SNYK_INTEGRATION_NAME_ENV, constants.SNYK_INTEGRATION_VERSION_ENV)} } if err == nil { // apply blacklist: ensure that no existing no_proxy or other configuration causes redirecting internal communication that is meant to stay between cliv1 and cliv2 blackList := []string{ - SNYK_HTTPS_PROXY_ENV, - SNYK_HTTP_PROXY_ENV, - SNYK_CA_CERTIFICATE_LOCATION_ENV, - SNYK_HTTP_NO_PROXY_ENV, - SNYK_NPM_NO_PROXY_ENV, - SNYK_NPM_HTTPS_PROXY_ENV, - SNYK_NPM_HTTP_PROXY_ENV, - SNYK_NPM_PROXY_ENV, - SNYK_NPM_ALL_PROXY, + constants.SNYK_HTTPS_PROXY_ENV, + constants.SNYK_HTTP_PROXY_ENV, + constants.SNYK_CA_CERTIFICATE_LOCATION_ENV, + constants.SNYK_HTTP_NO_PROXY_ENV, + constants.SNYK_NPM_NO_PROXY_ENV, + constants.SNYK_NPM_HTTPS_PROXY_ENV, + constants.SNYK_NPM_HTTP_PROXY_ENV, + constants.SNYK_NPM_PROXY_ENV, + constants.SNYK_NPM_ALL_PROXY, } for _, key := range blackList { @@ -219,9 +203,9 @@ func PrepareV1EnvironmentVariables(input []string, integrationName string, integ } // fill expected values - inputAsMap[SNYK_HTTPS_PROXY_ENV] = proxyAddress - inputAsMap[SNYK_HTTP_PROXY_ENV] = proxyAddress - inputAsMap[SNYK_CA_CERTIFICATE_LOCATION_ENV] = caCertificateLocation + inputAsMap[constants.SNYK_HTTPS_PROXY_ENV] = proxyAddress + inputAsMap[constants.SNYK_HTTP_PROXY_ENV] = proxyAddress + inputAsMap[constants.SNYK_CA_CERTIFICATE_LOCATION_ENV] = caCertificateLocation result = utils.ToSlice(inputAsMap, "=") } @@ -243,7 +227,7 @@ func PrepareV1Command(cmd string, args []string, proxyPort int, caCertLocation s return snykCmd, err } -func (c *CLI) executeV1Default(wrapperProxyPort int, fullPathToCert string, passthroughArgs []string) int { +func (c *CLI) executeV1Default(wrapperProxyPort int, fullPathToCert string, passthroughArgs []string) error { c.DebugLogger.Println("launching snyk with path: ", c.v1BinaryLocation) c.DebugLogger.Println("fullPathToCert:", fullPathToCert) @@ -253,7 +237,7 @@ func (c *CLI) executeV1Default(wrapperProxyPort int, fullPathToCert string, pass wrapperProxyPort, fullPathToCert, c.GetIntegrationName(), - c.GetFullVersion(), + GetFullVersion(), ) if err != nil { @@ -263,33 +247,39 @@ func (c *CLI) executeV1Default(wrapperProxyPort int, fullPathToCert string, pass } err = snykCmd.Run() - if err != nil { - if exitError, ok := err.(*exec.ExitError); ok { - exitCode := exitError.ExitCode() - return exitCode - } else { - // got an error but it's not an ExitError - fmt.Println(err) - return SNYK_EXIT_CODE_ERROR - } - } - return SNYK_EXIT_CODE_OK + return err } -func (c *CLI) Execute(wrapperProxyPort int, fullPathToCert string, passthroughArgs []string) int { +func (c *CLI) Execute(wrapperProxyPort int, fullPathToCert string, passthroughArgs []string) error { c.DebugLogger.Println("passthroughArgs", passthroughArgs) - returnCode := SNYK_EXIT_CODE_OK + var err error handler := determineHandler(passthroughArgs) switch { case handler == V2_VERSION: - returnCode = c.commandVersion(passthroughArgs) + err = c.commandVersion(passthroughArgs) case handler == V2_ABOUT: - returnCode = c.commandAbout(wrapperProxyPort, fullPathToCert, passthroughArgs) + err = c.commandAbout(wrapperProxyPort, fullPathToCert, passthroughArgs) default: - returnCode = c.executeV1Default(wrapperProxyPort, fullPathToCert, passthroughArgs) + err = c.executeV1Default(wrapperProxyPort, fullPathToCert, passthroughArgs) + } + + return err +} + +func (c *CLI) DeriveExitCode(err error) int { + returnCode := constants.SNYK_EXIT_CODE_OK + + if err != nil { + if exitError, ok := err.(*exec.ExitError); ok { + returnCode = exitError.ExitCode() + } else { + // got an error but it's not an ExitError + fmt.Println(err) + returnCode = constants.SNYK_EXIT_CODE_ERROR + } } return returnCode diff --git a/cliv2/internal/cliv2/cliv2_test.go b/cliv2/internal/cliv2/cliv2_test.go index 99c840484d..d117a27088 100644 --- a/cliv2/internal/cliv2/cliv2_test.go +++ b/cliv2/internal/cliv2/cliv2_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/snyk/cli/cliv2/internal/cliv2" + "github.com/snyk/cli/cliv2/internal/constants" "github.com/stretchr/testify/assert" ) @@ -106,16 +107,16 @@ func Test_executeRunV1(t *testing.T) { assert.NoDirExists(t, cacheDir) // create instance under test - cli := cliv2.NewCLIv2(cacheDir, logger) + cli, _ := cliv2.NewCLIv2(cacheDir, logger) // run once - actualReturnCode := cli.Execute(1000, "", []string{"--help"}) + actualReturnCode := cli.DeriveExitCode(cli.Execute(1000, "", []string{"--help"})) assert.Equal(t, expectedReturnCode, actualReturnCode) assert.FileExists(t, cli.GetBinaryLocation()) fileInfo1, _ := os.Stat(cli.GetBinaryLocation()) // run twice - actualReturnCode = cli.Execute(1000, "", []string{"--help"}) + actualReturnCode = cli.DeriveExitCode(cli.Execute(1000, "", []string{"--help"})) assert.Equal(t, expectedReturnCode, actualReturnCode) assert.FileExists(t, cli.GetBinaryLocation()) fileInfo2, _ := os.Stat(cli.GetBinaryLocation()) @@ -135,8 +136,8 @@ func Test_executeRunV2only(t *testing.T) { assert.NoDirExists(t, cacheDir) // create instance under test - cli := cliv2.NewCLIv2(cacheDir, logger) - actualReturnCode := cli.Execute(1000, "", []string{"--version"}) + cli, _ := cliv2.NewCLIv2(cacheDir, logger) + actualReturnCode := cli.DeriveExitCode(cli.Execute(1000, "", []string{"--version"})) assert.Equal(t, expectedReturnCode, actualReturnCode) assert.FileExists(t, cli.GetBinaryLocation()) @@ -152,11 +153,11 @@ func Test_executeEnvironmentError(t *testing.T) { assert.NoDirExists(t, cacheDir) // fill Environment Variable - os.Setenv(cliv2.SNYK_INTEGRATION_NAME_ENV, "someName") + os.Setenv(constants.SNYK_INTEGRATION_NAME_ENV, "someName") // create instance under test - cli := cliv2.NewCLIv2(cacheDir, logger) - actualReturnCode := cli.Execute(1000, "", []string{"--help"}) + cli, _ := cliv2.NewCLIv2(cacheDir, logger) + actualReturnCode := cli.DeriveExitCode(cli.Execute(1000, "", []string{"--help"})) assert.Equal(t, expectedReturnCode, actualReturnCode) assert.FileExists(t, cli.GetBinaryLocation()) @@ -164,14 +165,14 @@ func Test_executeEnvironmentError(t *testing.T) { } func Test_executeUnknownCommand(t *testing.T) { - expectedReturnCode := cliv2.SNYK_EXIT_CODE_ERROR + expectedReturnCode := constants.SNYK_EXIT_CODE_ERROR cacheDir := "dasda" logger := log.New(ioutil.Discard, "", 0) // create instance under test - cli := cliv2.NewCLIv2(cacheDir, logger) - actualReturnCode := cli.Execute(1000, "", []string{"bogusCommand"}) + cli, _ := cliv2.NewCLIv2(cacheDir, logger) + actualReturnCode := cli.DeriveExitCode(cli.Execute(1000, "", []string{"bogusCommand"})) assert.Equal(t, expectedReturnCode, actualReturnCode) os.RemoveAll(cacheDir) diff --git a/cliv2/internal/configuration/configuration.go b/cliv2/internal/configuration/configuration.go new file mode 100644 index 0000000000..d7dfee9eb5 --- /dev/null +++ b/cliv2/internal/configuration/configuration.go @@ -0,0 +1,150 @@ +package configuration + +import ( + "os" + "path" + "strconv" + "strings" + + "github.com/snyk/cli/cliv2/internal/constants" + "github.com/spf13/viper" +) + +const ( + API_URL string = "snyk_api" + AUTHENTICATION_TOKEN string = "token" + AUTHENTICATION_BEARER_TOKEN string = "bearer_token" + INTEGRATION_NAME string = "snyk_integration_name" + INTEGRATION_VERSION string = "snyk_integration_version" + ANALYTICS_DISABLED string = "snyk_disable_analytics" +) + +type Configuration interface { + Get(key string) interface{} + GetString(key string) string + GetBool(key string) bool +} + +type extendedViper struct { + viper *viper.Viper + alternativeKeys map[string][]string + defaultValues map[string]interface{} +} + +func determineBasePath() string { + homedir, err := os.UserHomeDir() + if err != nil { + return "." + } + + result := path.Join(homedir, ".config", "configstore") + return result +} + +func CreateConfigurationFile(filename string) (string, error) { + configPath := determineBasePath() + filepath := path.Join(configPath, filename) + + folder := path.Dir(filepath) + err := os.MkdirAll(folder, 0755) + if err != nil { + return "", err + } + + // create empty file + err = os.WriteFile(filepath, []byte{}, 0755) + if err != nil { + return "", err + } + + return filepath, err +} + +func NewFromFiles(files ...string) Configuration { + config := &extendedViper{ + viper: viper.New(), + } + + // prepare config files + for _, file := range files { + config.viper.SetConfigName(file) + } + + configPath := determineBasePath() + config.viper.AddConfigPath(configPath) + config.viper.AddConfigPath(".") + + // prepare environment variables + config.viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) + config.viper.AutomaticEnv() + + // Assign alternative keys to look up of the original is not found + config.alternativeKeys = make(map[string][]string) + config.alternativeKeys[AUTHENTICATION_TOKEN] = []string{"snyk_token", "snyk_cfg_api", "api"} + config.alternativeKeys[AUTHENTICATION_BEARER_TOKEN] = []string{"snyk_oauth_token", "snyk_docker_token"} + + // Assign default values + config.defaultValues = make(map[string]interface{}) + config.defaultValues[API_URL] = constants.SNYK_DEFAULT_API_URL + config.defaultValues[ANALYTICS_DISABLED] = false + + // read config files + config.viper.ReadInConfig() + + return config +} + +func New() Configuration { + config := NewFromFiles("snyk") + return config +} + +func (ev *extendedViper) Get(key string) interface{} { + + // try to lookup given key + result := ev.viper.Get(key) + + // try to lookup alternative keys if available + i := 0 + altKeys := ev.alternativeKeys[key] + altKeysSize := len(altKeys) + for result == nil && i < altKeysSize { + tempKey := altKeys[i] + result = ev.viper.Get(tempKey) + i++ + } + + if result == nil { + if ev.defaultValues[key] != nil { + result = ev.defaultValues[key] + } + } + + return result +} + +func (ev *extendedViper) GetString(key string) string { + result := ev.Get(key) + if result == nil { + return "" + } + return result.(string) +} + +func (ev *extendedViper) GetBool(key string) bool { + result := ev.Get(key) + if result == nil { + return false + } + + switch result.(type) { + case bool: + return result.(bool) + case string: + stringResult := result.(string) + boolResult, _ := strconv.ParseBool(stringResult) + return boolResult + } + + return false +} diff --git a/cliv2/internal/configuration/configuration_test.go b/cliv2/internal/configuration/configuration_test.go new file mode 100644 index 0000000000..408c078723 --- /dev/null +++ b/cliv2/internal/configuration/configuration_test.go @@ -0,0 +1,97 @@ +package configuration + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +const ( + TEST_FILENAME string = "test" + TEST_FILENAME_JSON string = "test.json" +) + +func prepareConfigstore(content string) error { + file, err := CreateConfigurationFile(TEST_FILENAME_JSON) + if err != nil { + return err + } + + // write content to file + err = ioutil.WriteFile(file, []byte(content), 0755) + return err +} + +func cleanupConfigstore() { + file, _ := CreateConfigurationFile(TEST_FILENAME_JSON) + os.RemoveAll(file) +} + +func Test_ConfigurationGet_AUTHENTICATION_TOKEN(t *testing.T) { + expectedValue := "mytoken" + expectedValue2 := "123456" + assert.Nil(t, prepareConfigstore(`{"api": "mytoken", "somethingElse": 12}`)) + + config := NewFromFiles("test") + actualValue := config.GetString(AUTHENTICATION_TOKEN) + assert.Equal(t, expectedValue, actualValue) + + os.Setenv("SNYK_TOKEN", expectedValue2) + actualValue = config.GetString(AUTHENTICATION_TOKEN) + assert.Equal(t, expectedValue2, actualValue) + + cleanupConfigstore() +} + +func Test_ConfigurationGet_AUTHENTICATION_BEARER_TOKEN(t *testing.T) { + expectedValue := "anotherToken" + expectedValueDocker := "dockerTocken" + assert.Nil(t, prepareConfigstore(`{"api": "mytoken", "somethingElse": 12}`)) + + config := NewFromFiles(TEST_FILENAME) + + os.Setenv("SNYK_OAUTH_TOKEN", expectedValue) + actualValue := config.GetString(AUTHENTICATION_BEARER_TOKEN) + assert.Equal(t, expectedValue, actualValue) + + os.Unsetenv("SNYK_OAUTH_TOKEN") + os.Setenv("SNYK_DOCKER_TOKEN", expectedValueDocker) + actualValue = config.GetString(AUTHENTICATION_BEARER_TOKEN) + assert.Equal(t, expectedValueDocker, actualValue) + + cleanupConfigstore() +} + +func Test_ConfigurationGet_ANALYTICS_DISABLED(t *testing.T) { + assert.Nil(t, prepareConfigstore(`{"snyk_oauth_token": "mytoken", "somethingElse": 12}`)) + + config := NewFromFiles(TEST_FILENAME) + + os.Setenv("SNYK_DISABLE_ANALYTICS", "1") + actualValue := config.GetBool(ANALYTICS_DISABLED) + assert.True(t, actualValue) + + os.Setenv("SNYK_DISABLE_ANALYTICS", "0") + actualValue = config.GetBool(ANALYTICS_DISABLED) + assert.False(t, actualValue) + + cleanupConfigstore() +} + +func Test_ConfigurationGet_unset(t *testing.T) { + assert.Nil(t, prepareConfigstore(`{"api": "mytoken", "somethingElse": 12}`)) + + config := NewFromFiles(TEST_FILENAME) + actualValue := config.Get("notthere") + assert.Nil(t, actualValue) + + actualValueString := config.GetString("notthere") + assert.Empty(t, actualValueString) + + actualValueBool := config.GetBool("notthere") + assert.False(t, actualValueBool) + + cleanupConfigstore() +} diff --git a/cliv2/internal/constants/constants.go b/cliv2/internal/constants/constants.go new file mode 100644 index 0000000000..76f253d5be --- /dev/null +++ b/cliv2/internal/constants/constants.go @@ -0,0 +1,17 @@ +package constants + +const SNYK_EXIT_CODE_OK = 0 +const SNYK_EXIT_CODE_ERROR = 2 +const SNYK_INTEGRATION_NAME = "CLI_V1_PLUGIN" +const SNYK_INTEGRATION_NAME_ENV = "SNYK_INTEGRATION_NAME" +const SNYK_INTEGRATION_VERSION_ENV = "SNYK_INTEGRATION_VERSION" +const SNYK_HTTPS_PROXY_ENV = "HTTPS_PROXY" +const SNYK_HTTP_PROXY_ENV = "HTTP_PROXY" +const SNYK_HTTP_NO_PROXY_ENV = "NO_PROXY" +const SNYK_NPM_PROXY_ENV = "NPM_CONFIG_PROXY" +const SNYK_NPM_HTTPS_PROXY_ENV = "NPM_CONFIG_HTTPS_PROXY" +const SNYK_NPM_HTTP_PROXY_ENV = "NPM_CONFIG_HTTP_PROXY" +const SNYK_NPM_NO_PROXY_ENV = "NPM_CONFIG_NO_PROXY" +const SNYK_NPM_ALL_PROXY = "ALL_PROXY" +const SNYK_CA_CERTIFICATE_LOCATION_ENV = "NODE_EXTRA_CA_CERTS" +const SNYK_DEFAULT_API_URL = "https://api.snyk.io" diff --git a/cliv2/internal/utils/api_tokens.go b/cliv2/internal/utils/api_tokens.go new file mode 100644 index 0000000000..ff8aabccb8 --- /dev/null +++ b/cliv2/internal/utils/api_tokens.go @@ -0,0 +1,22 @@ +package utils + +import ( + "fmt" + + "github.com/snyk/cli/cliv2/internal/configuration" +) + +func GetAuthHeader(config configuration.Configuration) string { + + bearerToken := config.GetString(configuration.AUTHENTICATION_BEARER_TOKEN) + if len(bearerToken) > 0 { + return fmt.Sprintf("Bearer %s", bearerToken) + } + + token := config.GetString(configuration.AUTHENTICATION_TOKEN) + if len(token) > 0 { + return fmt.Sprintf("token %s", token) + } + + return "" +} diff --git a/cliv2/scripts/prepare_licenses.sh b/cliv2/scripts/prepare_licenses.sh index 62473f19c4..433b4be5d3 100755 --- a/cliv2/scripts/prepare_licenses.sh +++ b/cliv2/scripts/prepare_licenses.sh @@ -15,7 +15,7 @@ PATH="$PATH:$GOBIN" go-licenses save ./... --save_path=./internal/embedded/_data manualLicenseDownload "https://raw.githubusercontent.com/davecgh/go-spew/master/LICENSE" github.com/davecgh/go-spew manualLicenseDownload "https://raw.githubusercontent.com/alexbrainman/sspi/master/LICENSE" github.com/alexbrainman/sspi manualLicenseDownload "https://raw.githubusercontent.com/pmezard/go-difflib/master/LICENSE" github.com/pmezard/go-difflib -manualLicenseDownload "https://raw.githubusercontent.com/go-yaml/yaml/v3.0.1/LICENSE" gopkg.in/yaml.v3 +manualLicenseDownload "https://raw.githubusercontent.com/go-yaml/yaml/v2.4.0/LICENSE" gopkg.in/yaml.v2 manualLicenseDownload "https://go.dev/LICENSE?m=text" go.dev # clean up and print result diff --git a/test/jest/acceptance/analytics.spec.ts b/test/jest/acceptance/analytics.spec.ts index 57fedd27da..860589e814 100644 --- a/test/jest/acceptance/analytics.spec.ts +++ b/test/jest/acceptance/analytics.spec.ts @@ -4,6 +4,7 @@ import { createProjectFromWorkspace, } from '../util/createProject'; import { runSnykCLI } from '../util/runSnykCLI'; +import { isCLIV2 } from '../util/isCLIV2'; jest.setTimeout(1000 * 30); @@ -47,7 +48,13 @@ describe('analytics module', () => { expect(code).toBe(0); + if (isCLIV2()) { + // in this case an extra analytics event is being sent, which needs to be dropped + server.popRequest(); + } + const lastRequest = server.popRequest(); + expect(lastRequest).toMatchObject({ headers: { host: 'localhost:12345', @@ -114,6 +121,11 @@ describe('analytics module', () => { expect(code).toBe(1); + if (isCLIV2()) { + // in this case an extra analytics event is being sent, which needs to be dropped + server.popRequest(); + } + const lastRequest = server.popRequest(); expect(lastRequest).toMatchObject({ headers: { @@ -185,6 +197,11 @@ describe('analytics module', () => { expect(code).toBe(2); + if (isCLIV2()) { + // in this case an extra analytics event is being sent, which needs to be dropped + server.popRequest(); + } + const lastRequest = server.popRequest(); expect(lastRequest).toMatchObject({ headers: { @@ -245,6 +262,11 @@ describe('analytics module', () => { expect(code).toBe(0); + if (isCLIV2()) { + // in this case an extra analytics event is being sent, which needs to be dropped + server.popRequest(); + } + const lastRequest = server.popRequest(); expect(lastRequest).toMatchObject({ headers: { @@ -288,6 +310,47 @@ describe('analytics module', () => { }); }); + it('sends analytics data with basic check only', async () => { + const project = await createProjectFromWorkspace('npm-package'); + const { code } = await runSnykCLI('', { + cwd: project.path(), + env, + }); + + expect(code).toBe(0); + + const lastRequest = server.popRequest(); + expect(lastRequest).toMatchObject({ + headers: { + host: 'localhost:12345', + 'content-length': expect.any(String), + authorization: 'token 123456789', + 'content-type': 'application/json; charset=utf-8', + 'x-snyk-cli-version': expect.stringMatching(/^(\d+\.){2}.*/), + }, + query: {}, + body: { + data: { + args: expect.any(Array), + ci: expect.any(Boolean), + command: expect.any(String), + durationMs: expect.any(Number), + id: expect.any(String), + integrationEnvironment: '', + integrationEnvironmentVersion: '', + integrationName: 'JENKINS', + integrationVersion: '1.2.3', + // prettier-ignore + metrics: expect.any(Object), + nodeVersion: expect.any(String), + os: expect.any(String), + standalone: expect.any(Boolean), + version: expect.stringMatching(/^(\d+\.){2}.*/), + }, + }, + }); + }); + it('uses OAUTH token if set', async () => { const project = await createProjectFromWorkspace('npm-package'); const { code } = await runSnykCLI('test woof', { diff --git a/test/jest/acceptance/snyk-test/protect-upgrade-notification.spec.ts b/test/jest/acceptance/snyk-test/protect-upgrade-notification.spec.ts index 27297dee00..1db02dde09 100644 --- a/test/jest/acceptance/snyk-test/protect-upgrade-notification.spec.ts +++ b/test/jest/acceptance/snyk-test/protect-upgrade-notification.spec.ts @@ -1,6 +1,7 @@ import { fakeServer } from '../../../acceptance/fake-server'; import { createProjectFromFixture } from '../../util/createProject'; import { runSnykCLI } from '../../util/runSnykCLI'; +import { isCLIV2 } from '../../util/isCLIV2'; jest.setTimeout(1000 * 30); @@ -51,6 +52,11 @@ describe('analytics module', () => { ); expect(stdout).toContain(project.path('package.json')); + if (isCLIV2()) { + // in this case an extra analytics event is being sent, which needs to be dropped + server.popRequest(); + } + const lastRequest = server.popRequest(); expect(lastRequest).toMatchObject({ query: {}, @@ -82,6 +88,11 @@ describe('analytics module', () => { ); expect(stdout).toContain(project.path('package.json')); + if (isCLIV2()) { + // in this case an extra analytics event is being sent, which needs to be dropped + server.popRequest(); + } + const lastRequest = server.popRequest(); expect(lastRequest).toMatchObject({ query: {}, @@ -128,6 +139,11 @@ describe('analytics module', () => { project.path('with-package-json-without-snyk-dep/package.json'), ); + if (isCLIV2()) { + // in this case an extra analytics event is being sent, which needs to be dropped + server.popRequest(); + } + const lastRequest = server.popRequest(); expect(lastRequest).toMatchObject({ query: {}, @@ -158,6 +174,11 @@ describe('analytics module', () => { ); expect(stdout).not.toContain(project.path('package.json')); + if (isCLIV2()) { + // in this case an extra analytics event is being sent, which needs to be dropped + server.popRequest(); + } + const lastRequest = server.popRequest(); expect(lastRequest).toMatchObject({ query: {}, From 9e1f2d7385a394623952fa8e15fb1c0ba06c710d Mon Sep 17 00:00:00 2001 From: Francesco Mari Date: Thu, 15 Sep 2022 08:38:57 +0200 Subject: [PATCH 34/55] feat: show Cloud Issues URL when sharing results with snyk iac test --- .../test/iac/local-execution/types.ts | 2 +- src/cli/commands/test/iac/output.ts | 32 +++++++++++++++++++ .../iac-output/text/share-results.ts | 20 ++++++++++++ src/lib/iac/test/v2/errors.ts | 3 +- .../policy-engine/constants/utils.ts | 12 +++---- src/lib/iac/test/v2/output.ts | 4 +-- 6 files changed, 63 insertions(+), 10 deletions(-) diff --git a/src/cli/commands/test/iac/local-execution/types.ts b/src/cli/commands/test/iac/local-execution/types.ts index 93d5b48687..458d64e0e1 100644 --- a/src/cli/commands/test/iac/local-execution/types.ts +++ b/src/cli/commands/test/iac/local-execution/types.ts @@ -390,7 +390,7 @@ export enum IaCErrorCodes { NoLoadableInput = 2114, FailedToMakeResourcesResolvers = 2115, ResourcesResolverError = 2116, - FailedToShareResults = 2200, + FailedToProcessResults = 2200, } export interface TestReturnValue { diff --git a/src/cli/commands/test/iac/output.ts b/src/cli/commands/test/iac/output.ts index e7bb37235b..4bae1e867c 100644 --- a/src/cli/commands/test/iac/output.ts +++ b/src/cli/commands/test/iac/output.ts @@ -32,6 +32,7 @@ import { shareResultsTip, formatTestData, } from '../../../../lib/formatters/iac-output/text'; +import { formatShareResultsOutputV2 } from '../../../../lib/formatters/iac-output/text/share-results'; const SEPARATOR = '\n-------------------------------------------------------\n'; @@ -269,6 +270,37 @@ export function buildShareResultsSummary({ return response; } +export function buildShareResultsSummaryV2({ + orgName, + projectName, + options, + isIacCustomRulesEntitlementEnabled, + isIacShareCliResultsCustomRulesSupported, +}: { + orgName: string; + projectName: string; + options: IaCTestFlags; + isIacCustomRulesEntitlementEnabled: boolean; + isIacShareCliResultsCustomRulesSupported: boolean; +}): string { + let response = ''; + + response += + SEPARATOR + EOL + formatShareResultsOutputV2(orgName, projectName); + + if ( + shouldPrintShareCustomRulesDisclaimer( + options, + isIacCustomRulesEntitlementEnabled, + isIacShareCliResultsCustomRulesSupported, + ) + ) { + response += EOL + EOL + shareCustomRulesDisclaimer; + } + + return response; +} + export function shouldPrintShareResultsTip(options: IaCTestFlags): boolean { return shouldLogUserMessages(options) && !options.report; } diff --git a/src/lib/formatters/iac-output/text/share-results.ts b/src/lib/formatters/iac-output/text/share-results.ts index c2ea465f01..f493bf7f3d 100644 --- a/src/lib/formatters/iac-output/text/share-results.ts +++ b/src/lib/formatters/iac-output/text/share-results.ts @@ -17,6 +17,26 @@ export function formatShareResultsOutput(orgName: string, projectName: string) { ); } +export function formatShareResultsOutputV2( + orgName: string, + projectName: string, +) { + return ( + colors.title('Report Complete') + + EOL + + EOL + + contentPadding + + 'Your test results are available at: ' + + colors.title( + `${ + config.ROOT + }/org/${orgName}/cloud/issues?environment_name=${encodeURIComponent( + projectName, + )}`, + ) + ); +} + export const shareResultsTip = colors.title('Tip') + EOL + diff --git a/src/lib/iac/test/v2/errors.ts b/src/lib/iac/test/v2/errors.ts index 661550741e..41d2b5f475 100644 --- a/src/lib/iac/test/v2/errors.ts +++ b/src/lib/iac/test/v2/errors.ts @@ -34,7 +34,8 @@ const snykIacTestErrorsUserMessages = { 'An error occurred preparing the requested cloud context. Please run the command again with the `-d` flag for more information.', ResourcesResolverError: 'An error occurred scanning cloud resources. Please run the command again with the `-d` flag for more information.', - FailedToShareResults: 'Failed to upload the test results with the platform', + FailedToProcessResults: + 'An error occurred while processing results. Please run the command again with the `-d` flag for more information.', }; export function getErrorUserMessage(code: number): string { diff --git a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts index f88c777c99..c73eefebd4 100644 --- a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts +++ b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts @@ -1,12 +1,12 @@ import * as os from 'os'; const policyEngineChecksums = ` -16211f1b806a85127cad2f1165e39a679a82c6c3d0d6a0bc4fde196710280b73 snyk-iac-test_0.31.2_Linux_x86_64 -931a8eb829c912251ae1d47c7b729148dca2bd3c60a4c8b564f614aeeee9d7c9 snyk-iac-test_0.31.2_Darwin_x86_64 -9536c5b4b4bf6fef94dd110033311b4447857c43bb07d64f5d2bc498cb53366b snyk-iac-test_0.31.2_Windows_arm64.exe -cf24c3b562f5c4282c029510cf679cabb5fa2a96bbf207cdd57f42e960173fb4 snyk-iac-test_0.31.2_Darwin_arm64 -d3bc0efa5e7eec34e9cd2f226e3686329e4a4f371e532851e4d10226e250505d snyk-iac-test_0.31.2_Linux_arm64 -fcebb81c0745d8636d55ac9aa4582acbc38d93a496970d3069c19ab278b5ebb6 snyk-iac-test_0.31.2_Windows_x86_64.exe +287c2b8c97b2b6208264e5bf9dab3132c34355efdecf29974a84bd56e7e1654d snyk-iac-test_0.31.3_Darwin_x86_64 +4cb497eac74ed543dde6935e5cc0519cffbcced6bfe9a98c697b125edfb75a2e snyk-iac-test_0.31.3_Linux_arm64 +6059e32181c32f364757cb39204beea73c1ed4c477d5ae8fa8e970d5c792bb37 snyk-iac-test_0.31.3_Darwin_arm64 +7767548480f2479205bdf3d792a66d43313717a471e1c300841504b63ae2581b snyk-iac-test_0.31.3_Windows_arm64.exe +8363ae002cf64f4bb0c65ddc2312d4c6b23098032983d61d8c4c439b705750ed snyk-iac-test_0.31.3_Windows_x86_64.exe +e36cc18b60f7b41fccf5a097f685f437813b9183aa9c6fa97ea4c1fe36ac0e42 snyk-iac-test_0.31.3_Linux_x86_64 `; export const policyEngineVersion = getPolicyEngineVersion(); diff --git a/src/lib/iac/test/v2/output.ts b/src/lib/iac/test/v2/output.ts index baf4e44154..52016c6f1b 100644 --- a/src/lib/iac/test/v2/output.ts +++ b/src/lib/iac/test/v2/output.ts @@ -26,7 +26,7 @@ import stripAnsi from 'strip-ansi'; import * as path from 'path'; import { getErrorStringCode } from '../../../../cli/commands/test/iac/local-execution/error-utils'; import { - buildShareResultsSummary, + buildShareResultsSummaryV2, shouldPrintShareResultsTip, } from '../../../../cli/commands/test/iac/output'; @@ -167,7 +167,7 @@ function buildTextOutput({ response += EOL; if (options.report) { - response += buildShareResultsSummary({ + response += buildShareResultsSummaryV2({ orgName: orgSettings.meta.org, projectName, options, From 875f0e98651892d77aabdc23296b5edf4e05a712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Scha=CC=88fer?= <101886095+PeterSchafer@users.noreply.github.com> Date: Thu, 15 Sep 2022 16:01:41 +0200 Subject: [PATCH 35/55] fix: upgrade go-httpauth to support basic auth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge and add proxy and proxy auth related tests Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> Signed-off-by: Peter Schäfer <101886095+PeterSchafer@users.noreply.github.com> --- cliv2/Makefile | 6 +- cliv2/go.mod | 2 +- cliv2/go.sum | 4 +- .../acceptance/proxy_authentication.spec.ts | 270 ---------------- .../fixtures/squid_environment/Dockerfile | 0 .../squid_environment/docker-compose.yml | 0 .../squid_environment/scripts/setup.sh | 0 test/jest/acceptance/proxy-behavior.spec.ts | 289 ++++++++++++++++++ 8 files changed, 293 insertions(+), 278 deletions(-) delete mode 100644 cliv2/test/acceptance/proxy_authentication.spec.ts rename {cliv2/test => test}/fixtures/squid_environment/Dockerfile (100%) rename {cliv2/test => test}/fixtures/squid_environment/docker-compose.yml (100%) rename {cliv2/test => test}/fixtures/squid_environment/scripts/setup.sh (100%) diff --git a/cliv2/Makefile b/cliv2/Makefile index 4859d7ba16..846f0b446c 100644 --- a/cliv2/Makefile +++ b/cliv2/Makefile @@ -190,12 +190,8 @@ whiteboxtest: @echo "$(LOG_PREFIX) Running $@" @$(GOCMD) test -cover ./... -.PHONY: acceptancetest -acceptancetest: build - TEST_SNYK_COMMAND="$(BUILD_DIR)/$(V2_EXECUTABLE_NAME)" npx jest - .PHONY: test -test: whiteboxtest blackboxtest acceptancetest +test: whiteboxtest blackboxtest .PHONY: lint lint: diff --git a/cliv2/go.mod b/cliv2/go.mod index 548439b1b8..1a0bb789ed 100644 --- a/cliv2/go.mod +++ b/cliv2/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/elazarl/goproxy v0.0.0-20220328115640-894aeddb713e github.com/hashicorp/go-uuid v1.0.3 - github.com/snyk/go-httpauth v0.0.0-20220912133144-d51219ca664d + github.com/snyk/go-httpauth v0.0.0-20220915135832-0edf62cf8cdd github.com/spf13/viper v1.13.0 github.com/stretchr/testify v1.8.0 ) diff --git a/cliv2/go.sum b/cliv2/go.sum index d8458b29b9..34b23561ca 100644 --- a/cliv2/go.sum +++ b/cliv2/go.sum @@ -174,8 +174,8 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/snyk/go-httpauth v0.0.0-20220912133144-d51219ca664d h1:dT2rfoDxGDWeplsnXWajWZcZ7zo8R6Hif3jufvkXcUE= -github.com/snyk/go-httpauth v0.0.0-20220912133144-d51219ca664d/go.mod h1:v6t6wKizOcHXT3p4qKn6Bda7yNIjCQ54Xyl31NjgXkY= +github.com/snyk/go-httpauth v0.0.0-20220915135832-0edf62cf8cdd h1:zjDhcQ642rIVI8aIjfG5uVcw+OGotQtX2l9VHe7IqCQ= +github.com/snyk/go-httpauth v0.0.0-20220915135832-0edf62cf8cdd/go.mod h1:v6t6wKizOcHXT3p4qKn6Bda7yNIjCQ54Xyl31NjgXkY= github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= diff --git a/cliv2/test/acceptance/proxy_authentication.spec.ts b/cliv2/test/acceptance/proxy_authentication.spec.ts deleted file mode 100644 index 1753911092..0000000000 --- a/cliv2/test/acceptance/proxy_authentication.spec.ts +++ /dev/null @@ -1,270 +0,0 @@ -import * as path from 'path'; -import { fakeServer, FakeServer } from '../../../test/acceptance/fake-server'; -import { - createProjectFromWorkspace, - TestProject, -} from '../../../test/jest/util/createProject'; -import { - startCommand, - TestCLI, - startSnykCLI, -} from '../../../test/jest/util/startSnykCLI'; -import { isCLIV2 } from '../../../test/jest/util/isCLIV2'; -import { unlink } from 'fs'; -import { execSync } from 'child_process'; -import * as os from 'os'; - -jest.setTimeout(1000 * 60); - -// Global test configuration -const rootDir = path.resolve(path.join(__dirname, '..', '..')); -const squidEnvironmentPath = path.resolve( - path.join(rootDir, 'test', 'fixtures', 'squid_environment'), -); -const dockerComposeFile = path.resolve( - path.join(squidEnvironmentPath, 'docker-compose.yml'), -); -const scriptsPath = path.resolve(path.join(squidEnvironmentPath, 'scripts')); -const containerName = 'proxy_authentication_container'; -const hostnameFakeServer = 'host.docker.internal'; -const hostnameProxy = 'proxy.snyk.local'; -const proxyPort = '3128'; -const port = process.env.PORT || process.env.SNYK_PORT || '12345'; -const baseApi = '/api/v1'; -const SNYK_API = 'http://' + hostnameFakeServer + ':' + port + baseApi; -const HTTP_PROXY = 'http://localhost:' + proxyPort; -const KRB5_CACHE_FILE = 'krb5_cache'; -const KRB5_CONFIG_FILE = 'krb5.conf'; - -function getDockerOptions() { - const dockerOptions = { - env: { - ...process.env, - HTTP_PROXY_PORT: proxyPort, - PROXY_HOSTNAME: hostnameProxy, - SNYK_API: SNYK_API, - CONTAINER_NAME: containerName, - SCRIPTS_PATH: scriptsPath, - }, - }; - return dockerOptions; -} - -function isDockerAvailable(): boolean { - let result = false; - - try { - execSync('docker --version'); - execSync('docker-compose --version'); - result = true; - } catch (error) { - result = false; - console.debug(error); - } - - return result; -} - -async function startProxyEnvironment(): Promise { - // Stop any orphaned containers from previous runs. - await stopProxyEnvironment(); - - const dockerUp = await startCommand( - 'docker-compose', - ['--file', dockerComposeFile, 'up', '--build'], - getDockerOptions(), - ); - await expect(dockerUp).toDisplay('Kerberos setup complete.', { - timeout: 60_000, - }); -} - -async function stopProxyEnvironment(): Promise { - const dockerDown = await startCommand( - 'docker-compose', - ['--file', dockerComposeFile, 'down'], - getDockerOptions(), - ); - await expect(dockerDown).toExitWith(0, { timeout: 30_000 }); -} - -async function getProxyAccessLog(): Promise { - const check = await startCommand('docker', [ - 'exec', - containerName, - 'cat', - '/var/log/squid/access.log', - ]); - await expect(check).toExitWith(0); - return check.stdout.get(); -} - -async function runCliWithProxy( - env: Record, - args: string[] = [], - cmd = 'test', -): Promise { - let temp: string[] = [cmd, '--debug']; - temp = temp.concat(args); - - if (env['KRB5CCNAME'] == undefined) { - env['KRB5CCNAME'] = 'FILE:' + path.join(scriptsPath, KRB5_CACHE_FILE); - env['KRB5_CONFIG'] = path.join(scriptsPath, KRB5_CONFIG_FILE); - } - - const cli = await startSnykCLI(temp.join(' '), { - env: { - ...env, - SNYK_HTTP_PROTOCOL_UPGRADE: '0', - }, - }); - return cli; -} - -function canTestRun(): boolean { - if (!isCLIV2() || !isDockerAvailable()) { - // eslint-disable-next-line jest/no-focused-tests - it.only('These tests are currently limited to certain environments.', () => { - console.warn( - 'Skipping CLIv2 test. These tests are limited to environments that have docker and docker-compose installed.', - ); - }); - return false; - } - return true; -} - -describe('Proxy Authentication (all platforms)', () => { - if (canTestRun()) { - let server: FakeServer; - let env: Record; - let project: TestProject; - - beforeAll(async () => { - project = await createProjectFromWorkspace('npm-package'); - await startProxyEnvironment(); - - env = { - ...process.env, - SNYK_API: SNYK_API, - SNYK_TOKEN: '123456789', - HTTP_PROXY: HTTP_PROXY, - HTTPS_PROXY: HTTP_PROXY, - }; - server = fakeServer(baseApi, env.SNYK_TOKEN); - await server.listenPromise(port); - }); - - afterEach(() => { - server.restore(); - }); - - afterAll(async () => { - await server.closePromise(); - await stopProxyEnvironment(); - unlink(path.join(scriptsPath, KRB5_CACHE_FILE), () => {}); - unlink(path.join(scriptsPath, KRB5_CONFIG_FILE), () => {}); - }); - - it('fails to run snyk test due to disabled proxy authentication', async () => { - const logOnEntry = await getProxyAccessLog(); - - // run snyk test - const args: string[] = ['--proxy-noauth', project.path()]; - const cli = await runCliWithProxy(env, args); - await expect(cli).toExitWith(2); - - const logOnExit = await getProxyAccessLog(); - const additionalLogEntries = logOnExit.substring(logOnEntry.length); - expect(additionalLogEntries.includes('TCP_DENIED/407')).toBeTruthy(); - expect( - additionalLogEntries.includes( - 'CONNECT ' + hostnameFakeServer + ':' + port, - ), - ).toBeFalsy(); - }); - - it('successfully runs snyk test with proxy', async () => { - const logOnEntry = await getProxyAccessLog(); - - // run snyk test - const args: string[] = [project.path()]; - const cli = await runCliWithProxy(env, args); - await expect(cli).toExitWith(0); - - const logOnExit = await getProxyAccessLog(); - const additionalLogEntries = logOnExit.substring(logOnEntry.length); - expect(additionalLogEntries.includes('TCP_TUNNEL/200')).toBeTruthy(); - expect( - additionalLogEntries.includes( - 'CONNECT ' + hostnameFakeServer + ':' + port, - ), - ).toBeTruthy(); - }); - } -}); - -describe('Proxy Authentication (Non-Windows)', () => { - if (canTestRun() && !os.platform().includes('win32')) { - let server: FakeServer; - let env: Record; - let project: TestProject; - - beforeAll(async () => { - project = await createProjectFromWorkspace('npm-package'); - await startProxyEnvironment(); - - env = { - ...process.env, - SNYK_API: SNYK_API, - SNYK_TOKEN: '123456789', - HTTP_PROXY: HTTP_PROXY, - HTTPS_PROXY: HTTP_PROXY, - }; - server = fakeServer(baseApi, env.SNYK_TOKEN); - await server.listenPromise(port); - }); - - afterEach(() => { - server.restore(); - }); - - afterAll(async () => { - await server.closePromise(); - await stopProxyEnvironment(); - unlink(path.join(scriptsPath, KRB5_CACHE_FILE), () => {}); - unlink(path.join(scriptsPath, KRB5_CONFIG_FILE), () => {}); - }); - - it('fail to run snyk test with proxy due to incorrect cache configuration', async () => { - const logOnEntry = await getProxyAccessLog(); - - // run snyk test - const args: string[] = [project.path()]; - env['KRB5CCNAME'] = 'MEMORY:' + path.join(scriptsPath, KRB5_CACHE_FILE); // specifying incorrect cache type memory - env['KRB5_CONFIG'] = path.join(scriptsPath, KRB5_CONFIG_FILE); - const cli = await runCliWithProxy(env, args); - await expect(cli).toExitWith(2); - - const logOnExit = await getProxyAccessLog(); - const additionalLogEntries = logOnExit.substring(logOnEntry.length); - expect(additionalLogEntries.includes('TCP_DENIED/407')).toBeTruthy(); - }); - - it('fail to run snyk test with proxy due to incorrect config file', async () => { - const logOnEntry = await getProxyAccessLog(); - - // run snyk test - const args: string[] = [project.path()]; - env['KRB5CCNAME'] = 'FILE:' + path.join(scriptsPath, KRB5_CACHE_FILE); - env['KRB5_CONFIG'] = - path.join(scriptsPath, KRB5_CONFIG_FILE) + '_not_existing'; // specifying incorrect config location - const cli = await runCliWithProxy(env, args); - await expect(cli).toExitWith(2); - - const logOnExit = await getProxyAccessLog(); - const additionalLogEntries = logOnExit.substring(logOnEntry.length); - expect(additionalLogEntries.includes('TCP_DENIED/407')).toBeTruthy(); - }); - } -}); diff --git a/cliv2/test/fixtures/squid_environment/Dockerfile b/test/fixtures/squid_environment/Dockerfile similarity index 100% rename from cliv2/test/fixtures/squid_environment/Dockerfile rename to test/fixtures/squid_environment/Dockerfile diff --git a/cliv2/test/fixtures/squid_environment/docker-compose.yml b/test/fixtures/squid_environment/docker-compose.yml similarity index 100% rename from cliv2/test/fixtures/squid_environment/docker-compose.yml rename to test/fixtures/squid_environment/docker-compose.yml diff --git a/cliv2/test/fixtures/squid_environment/scripts/setup.sh b/test/fixtures/squid_environment/scripts/setup.sh similarity index 100% rename from cliv2/test/fixtures/squid_environment/scripts/setup.sh rename to test/fixtures/squid_environment/scripts/setup.sh diff --git a/test/jest/acceptance/proxy-behavior.spec.ts b/test/jest/acceptance/proxy-behavior.spec.ts index fe94b87412..66290069c3 100644 --- a/test/jest/acceptance/proxy-behavior.spec.ts +++ b/test/jest/acceptance/proxy-behavior.spec.ts @@ -1,5 +1,19 @@ import { runSnykCLI } from '../util/runSnykCLI'; import { isCLIV2 } from '../util/isCLIV2'; +import { fakeServer, FakeServer } from '../../../test/acceptance/fake-server'; +import * as path from 'path'; +import { + createProjectFromWorkspace, + TestProject, +} from '../../../test/jest/util/createProject'; +import { + startCommand, + TestCLI, + startSnykCLI, +} from '../../../test/jest/util/startSnykCLI'; +import { unlink } from 'fs'; +import { execSync } from 'child_process'; +import * as os from 'os'; const fakeServerPort = 12345; const SNYK_API_HTTPS = 'https://snyk.io/api/v1'; @@ -24,6 +38,125 @@ function getConnectionRefusedRegExp(): string | RegExp { return expectedMessageRegex; } +// Global test configuration +const rootDir = path.resolve(path.join(__dirname, '..', '..')); +const squidEnvironmentPath = path.resolve( + path.join(rootDir, 'fixtures', 'squid_environment'), +); +const dockerComposeFile = path.resolve( + path.join(squidEnvironmentPath, 'docker-compose.yml'), +); +const scriptsPath = path.resolve(path.join(squidEnvironmentPath, 'scripts')); +const containerName = 'proxy_authentication_container'; +const hostnameFakeServer = 'host.docker.internal'; +const hostnameProxy = 'proxy.snyk.local'; +const proxyPort = '3128'; +const port = process.env.PORT || process.env.SNYK_PORT || '12345'; +const baseApi = '/api/v1'; +const SNYK_API = 'http://' + hostnameFakeServer + ':' + port + baseApi; +const HTTP_PROXY_WITH_USER = 'http://patch:dogsrule@localhost:' + proxyPort; +const HTTP_PROXY = 'http://localhost:' + proxyPort; +const KRB5_CACHE_FILE = 'krb5_cache'; +const KRB5_CONFIG_FILE = 'krb5.conf'; + +function getDockerOptions() { + const dockerOptions = { + env: { + ...process.env, + HTTP_PROXY_PORT: proxyPort, + PROXY_HOSTNAME: hostnameProxy, + SNYK_API: SNYK_API, + CONTAINER_NAME: containerName, + SCRIPTS_PATH: scriptsPath, + }, + }; + return dockerOptions; +} + +function isDockerAvailable(): boolean { + let result = false; + + try { + execSync('docker ps'); + execSync('docker-compose --version'); + result = true; + } catch (error) { + result = false; + console.debug(error); + } + + return result; +} + +async function startProxyEnvironment(): Promise { + // Stop any orphaned containers from previous runs. + await stopProxyEnvironment(); + + const dockerUp = await startCommand( + 'docker-compose', + ['--file', dockerComposeFile, 'up', '--build'], + getDockerOptions(), + ); + await expect(dockerUp).toDisplay('Kerberos setup complete.', { + timeout: 60_000, + }); +} + +async function stopProxyEnvironment(): Promise { + const dockerDown = await startCommand( + 'docker-compose', + ['--file', dockerComposeFile, 'down'], + getDockerOptions(), + ); + await expect(dockerDown).toExitWith(0, { timeout: 30_000 }); +} + +async function getProxyAccessLog(): Promise { + const check = await startCommand('docker', [ + 'exec', + containerName, + 'cat', + '/var/log/squid/access.log', + ]); + await expect(check).toExitWith(0); + return check.stdout.get(); +} + +async function runCliWithProxy( + env: Record, + args: string[] = [], + cmd = 'test', +): Promise { + let temp: string[] = [cmd, '--debug']; + temp = temp.concat(args); + + if (env['KRB5CCNAME'] == undefined) { + env['KRB5CCNAME'] = 'FILE:' + path.join(scriptsPath, KRB5_CACHE_FILE); + env['KRB5_CONFIG'] = path.join(scriptsPath, KRB5_CONFIG_FILE); + } + + const cli = await startSnykCLI(temp.join(' '), { + env: { + ...env, + SNYK_HTTP_PROTOCOL_UPGRADE: '0', + }, + }); + return cli; +} + +function canTestRun(): boolean { + if (!isDockerAvailable()) { + // eslint-disable-next-line jest/no-focused-tests + it('These tests are currently limited to certain environments.', () => { + console.warn( + 'Skipping CLIv2 test. These tests are limited to environments that have docker and docker-compose installed.', + ); + }); + return false; + } + return true; +} + jest.setTimeout(1000 * 60 * 1); describe('Proxy configuration behavior', () => { describe('*_PROXY against HTTPS host', () => { @@ -116,3 +249,159 @@ describe('Proxy configuration behavior', () => { } }); }); + +describe('Proxy Authentication (all platforms)', () => { + if (canTestRun()) { + let server: FakeServer; + let env: Record; + let project: TestProject; + + beforeAll(async () => { + project = await createProjectFromWorkspace('npm-package'); + await startProxyEnvironment(); + + env = { + ...process.env, + SNYK_API: SNYK_API, + SNYK_TOKEN: '123456789', + HTTP_PROXY: HTTP_PROXY, + HTTPS_PROXY: HTTP_PROXY, + }; + server = fakeServer(baseApi, env.SNYK_TOKEN); + await server.listenPromise(port); + }); + + afterEach(() => { + server.restore(); + }); + + afterAll(async () => { + await server.closePromise(); + await stopProxyEnvironment(); + unlink(path.join(scriptsPath, KRB5_CACHE_FILE), () => {}); + unlink(path.join(scriptsPath, KRB5_CONFIG_FILE), () => {}); + }); + + if (isCLIV2()) { + it('fails to run snyk test due to disabled proxy authentication', async () => { + const logOnEntry = await getProxyAccessLog(); + + // run snyk test + const args: string[] = ['--proxy-noauth', project.path()]; + const cli = await runCliWithProxy(env, args); + await expect(cli).toExitWith(2); + + const logOnExit = await getProxyAccessLog(); + const additionalLogEntries = logOnExit.substring(logOnEntry.length); + expect(additionalLogEntries.includes('TCP_DENIED/407')).toBeTruthy(); + expect( + additionalLogEntries.includes( + 'CONNECT ' + hostnameFakeServer + ':' + port, + ), + ).toBeFalsy(); + }); + + it('successfully runs snyk test with proxy (AnyAuth)', async () => { + const logOnEntry = await getProxyAccessLog(); + + // run snyk test + const args: string[] = [project.path()]; + const cli = await runCliWithProxy(env, args); + await expect(cli).toExitWith(0); + + const logOnExit = await getProxyAccessLog(); + const additionalLogEntries = logOnExit.substring(logOnEntry.length); + expect(additionalLogEntries.includes('TCP_TUNNEL/200')).toBeTruthy(); + expect( + additionalLogEntries.includes( + 'CONNECT ' + hostnameFakeServer + ':' + port, + ), + ).toBeTruthy(); + }); + } + + it('successfully runs snyk test with proxy (Basic)', async () => { + const logOnEntry = await getProxyAccessLog(); + + const localEnv = env; + localEnv['HTTP_PROXY'] = HTTP_PROXY_WITH_USER; + localEnv['HTTPS_PROXY'] = HTTP_PROXY_WITH_USER; + localEnv['SNYK_API'] = SNYK_API_HTTPS; + + // run snyk test + const args: string[] = [project.path(), '-d']; + const cli = await runCliWithProxy(localEnv, args, 'woof'); + await expect(cli).toExitWith(0); + + const logOnExit = await getProxyAccessLog(); + const additionalLogEntries = logOnExit.substring(logOnEntry.length); + expect(additionalLogEntries.includes('TCP_TUNNEL/200')).toBeTruthy(); + expect(additionalLogEntries.includes('CONNECT snyk.io:443')).toBeTruthy(); + }); + } +}); + +describe('Proxy Authentication (Non-Windows)', () => { + if (canTestRun() && !os.platform().includes('win32') && isCLIV2()) { + let server: FakeServer; + let env: Record; + let project: TestProject; + + beforeAll(async () => { + project = await createProjectFromWorkspace('npm-package'); + await startProxyEnvironment(); + + env = { + ...process.env, + SNYK_API: SNYK_API, + SNYK_TOKEN: '123456789', + HTTP_PROXY: HTTP_PROXY, + HTTPS_PROXY: HTTP_PROXY, + }; + server = fakeServer(baseApi, env.SNYK_TOKEN); + await server.listenPromise(port); + }); + + afterEach(() => { + server.restore(); + }); + + afterAll(async () => { + await server.closePromise(); + await stopProxyEnvironment(); + unlink(path.join(scriptsPath, KRB5_CACHE_FILE), () => {}); + unlink(path.join(scriptsPath, KRB5_CONFIG_FILE), () => {}); + }); + + it('fail to run snyk test with proxy due to incorrect cache configuration', async () => { + const logOnEntry = await getProxyAccessLog(); + + // run snyk test + const args: string[] = [project.path()]; + env['KRB5CCNAME'] = 'MEMORY:' + path.join(scriptsPath, KRB5_CACHE_FILE); // specifying incorrect cache type memory + env['KRB5_CONFIG'] = path.join(scriptsPath, KRB5_CONFIG_FILE); + const cli = await runCliWithProxy(env, args); + await expect(cli).toExitWith(2); + + const logOnExit = await getProxyAccessLog(); + const additionalLogEntries = logOnExit.substring(logOnEntry.length); + expect(additionalLogEntries.includes('TCP_DENIED/407')).toBeTruthy(); + }); + + it('fail to run snyk test with proxy due to incorrect config file', async () => { + const logOnEntry = await getProxyAccessLog(); + + // run snyk test + const args: string[] = [project.path()]; + env['KRB5CCNAME'] = 'FILE:' + path.join(scriptsPath, KRB5_CACHE_FILE); + env['KRB5_CONFIG'] = + path.join(scriptsPath, KRB5_CONFIG_FILE) + '_not_existing'; // specifying incorrect config location + const cli = await runCliWithProxy(env, args); + await expect(cli).toExitWith(2); + + const logOnExit = await getProxyAccessLog(); + const additionalLogEntries = logOnExit.substring(logOnEntry.length); + expect(additionalLogEntries.includes('TCP_DENIED/407')).toBeTruthy(); + }); + } +}); From 5f5fac4b0cdbfe7b6054ba02f86fe91841acd4a5 Mon Sep 17 00:00:00 2001 From: maxjeffos <44034094+maxjeffos@users.noreply.github.com> Date: Thu, 15 Sep 2022 14:51:56 -0400 Subject: [PATCH 36/55] chore: remove cliv2 filter from CI --- .circleci/config.yml | 46 ++++---------------------------------------- 1 file changed, 4 insertions(+), 42 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 154a0de6fc..81e977483e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -859,13 +859,6 @@ workflows: name: Version requires: - Build - filters: - branches: - only: - - /^chore\/.+$/ - - /^.*test.*$/ - - /^.*cliv2.*$/ - - master - build-artifact: name: Build (<< matrix.artifact >>) requires: @@ -963,62 +956,36 @@ workflows: # - v2-lint: name: v2 / Lint - filters: - branches: - only: - - /^.*cliv2.*$/ - - master - v2-unit-test: name: v2 / Unit Tests - filters: - branches: - only: - - /^.*cliv2.*$/ - - master - v2-build-artifact: name: v2 / Build (linux/amd64) requires: - Build (snyk-linux) go_os: linux go_arch: amd64 - filters: - branches: - only: - - /^.*cliv2.*$/ - - master - v2-build-artifact: name: v2 / Build (linux/arm64) requires: - Build (snyk-linux-arm64) go_os: linux go_arch: arm64 - filters: - branches: - only: - - /^.*cliv2.*$/ - - master - v2-build-artifact: name: v2 / Build (darwin/amd64) requires: - Build (snyk-macos) go_os: darwin go_arch: amd64 - filters: - branches: - only: - - /^.*cliv2.*$/ - - master - v2-build-artifact: name: v2 / Build (windows/amd64) requires: - Build (snyk-win.exe) go_os: windows go_arch: amd64 - filters: - branches: - only: - - /^.*cliv2.*$/ - - master + - v2-rename-windows-artifact: + name: v2 / Rename windows/amd64 artifact + requires: + - v2 / Sign (windows/amd64) - v2-build-artifact: name: v2 / Build (alpine/amd64) requires: @@ -1026,11 +993,6 @@ workflows: go_os: alpine go_arch: amd64 c_compiler: /usr/bin/musl-gcc - filters: - branches: - only: - - /^.*cliv2.*$/ - - master - v2-test-linux-amd64: name: v2 / Integration Tests (linux/amd64) requires: From 7e4133c872990a505a48b31b8de87f103382ed92 Mon Sep 17 00:00:00 2001 From: maxjeffos <44034094+maxjeffos@users.noreply.github.com> Date: Thu, 15 Sep 2022 14:53:42 -0400 Subject: [PATCH 37/55] chore: add golang binary for windows to releases --- .circleci/config.yml | 49 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 81e977483e..6df0bae78c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -533,6 +533,12 @@ jobs: - attach_workspace: at: . - setup_npm + - run: + name: Copy Windows cliv2 binaries to binary-releases staging area + command: | + ls -la cliv2/bin + cp cliv2/bin/snyk-win.exe binary-releases/snyk-win.exe + cp cliv2/bin/snyk-win.exe.sha256 binary-releases/snyk-win.exe.sha256 - run: name: Signing shasums command: make binary-releases/sha256sums.txt.asc @@ -667,6 +673,34 @@ jobs: paths: - ./cliv2/bin + v2-rename-windows-artifact: + executor: linux + working_directory: /home/circleci/snyk + steps: + - checkout + - attach_workspace: + at: . + - run: + name: Rename snyk_windows_amd64.exe artifact + command: mv snyk_windows_amd64.exe snyk-win.exe + working_directory: ./cliv2/bin + - run: + name: Regenerate sha256 + command: | + shasum -a 256 snyk-win.exe > snyk-win.exe.sha256 + shasum -a 256 -c snyk-win.exe.sha256 + working_directory: ./cliv2/bin + - run: + name: Show files + command: | + ls -la + cat snyk-win.exe.sha256 + working_directory: ./cliv2/bin + - persist_to_workspace: + root: . + paths: + - ./cliv2/bin + v2-prepare-release: executor: linux working_directory: /home/circleci/snyk @@ -755,7 +789,7 @@ jobs: name: Run integration tests working_directory: ./cliv2 environment: - TEST_SNYK_EXECUTABLE_PATH: ./bin/snyk_windows_amd64.exe + TEST_SNYK_EXECUTABLE_PATH: ./bin/snyk-win.exe command: | $env:SNYK_TOKEN = $env:SNYK_API_KEY ./bin/snyk_tests_windows_amd64.exe @@ -772,7 +806,7 @@ jobs: name: Run integration tests working_directory: ./cliv2 environment: - TEST_SNYK_EXECUTABLE_PATH: ./bin/snyk_windows_amd64.exe + TEST_SNYK_EXECUTABLE_PATH: ./bin/snyk-win.exe HTTPS_PROXY: http://localhost:8080 command: | $env:SNYK_TOKEN = $env:SNYK_API_KEY @@ -923,6 +957,7 @@ workflows: - Build (snyk-for-docker-desktop-darwin-x64.tar.gz) - Build (snyk-for-docker-desktop-darwin-arm64.tar.gz) - Build (docker-mac-signed-bundle.tar.gz) + - v2 / Prepare Release - should-release: name: Release? type: approval @@ -1012,11 +1047,11 @@ workflows: - v2-test-windows-amd64: name: v2 / Integration Tests (windows/amd64) requires: - - v2 / Build (windows/amd64) + - v2 / Rename windows/amd64 artifact - v2-test-proxy-windows-amd64: name: v2 / Proxy Integration Tests (windows/amd64) requires: - - v2 / Build (windows/amd64) + - v2 / Rename windows/amd64 artifact # Tests for backwards compatibility with CLIv1 - test-alpine: name: v2 / Jest Acceptance Tests (alpine/amd64) @@ -1040,8 +1075,8 @@ workflows: name: v2 / Jest Acceptance Tests (windows/amd64) context: nodejs-install requires: - - v2 / Build (windows/amd64) - test_snyk_command: C:\Users\circleci\snyk\cliv2\bin\snyk_windows_amd64.exe + - v2 / Rename windows/amd64 artifact + test_snyk_command: C:\Users\circleci\snyk\cliv2\bin\snyk-win.exe - test-macos: name: v2 / Jest Acceptance Tests (darwin/amd64) context: nodejs-install @@ -1071,4 +1106,4 @@ workflows: - v2 / Build (linux/amd64) - v2 / Build (linux/arm64) - v2 / Sign (darwin/amd64) - - v2 / Sign (windows/amd64) + - v2 / Rename windows/amd64 artifact From 55b6fbb7dfeba58c0d20d82eddb9720faf7b0fd9 Mon Sep 17 00:00:00 2001 From: David Agrest Date: Sun, 7 Aug 2022 19:04:18 +0300 Subject: [PATCH 38/55] feat: add unmanaged service test call ff --- src/lib/ecosystems/resolve-test-facts.ts | 212 +++++++++++++- src/lib/ecosystems/types.ts | 4 +- src/lib/ecosystems/unmanaged/types.ts | 264 ++++++++++++++++++ src/lib/ecosystems/unmanaged/utils.ts | 80 ++++++ src/lib/polling/polling-test.ts | 82 ++++++ src/lib/snyk-test/legacy.ts | 2 +- .../fixtures/create-dep-graph-response.ts | 8 + .../ecosystems/fixtures/dep-graph-open-api.ts | 69 +++++ .../fixtures/expected-test-result-new-impl.ts | 153 ++++++++++ .../fixtures/get-dep-graph-response.ts | 16 ++ .../ecosystems/fixtures/issues-response.ts | 95 +++++++ .../lib/ecosystems/resolve-test-facts.spec.ts | 229 +++++++++++++++ 12 files changed, 1210 insertions(+), 4 deletions(-) create mode 100644 src/lib/ecosystems/unmanaged/types.ts create mode 100644 src/lib/ecosystems/unmanaged/utils.ts create mode 100644 test/jest/unit/lib/ecosystems/fixtures/create-dep-graph-response.ts create mode 100644 test/jest/unit/lib/ecosystems/fixtures/dep-graph-open-api.ts create mode 100644 test/jest/unit/lib/ecosystems/fixtures/expected-test-result-new-impl.ts create mode 100644 test/jest/unit/lib/ecosystems/fixtures/get-dep-graph-response.ts create mode 100644 test/jest/unit/lib/ecosystems/fixtures/issues-response.ts diff --git a/src/lib/ecosystems/resolve-test-facts.ts b/src/lib/ecosystems/resolve-test-facts.ts index 8d9f001a1e..91cd787b7c 100644 --- a/src/lib/ecosystems/resolve-test-facts.ts +++ b/src/lib/ecosystems/resolve-test-facts.ts @@ -1,14 +1,36 @@ import { Options, PolicyOptions } from '../types'; import { spinner } from '../../lib/spinner'; -import { Ecosystem, ScanResult, TestResult } from './types'; +import { + Ecosystem, + ScanResult, + TestResult, + FileSignaturesDetails, +} from './types'; +import { + CreateDepGraphResponse, + GetIssuesResponse, + FileHashes, + Attributes, +} from './unmanaged/types'; import { requestTestPollingToken, pollingTestWithTokenUntilDone, + createDepGraph, + getDepGraph, + getIssues, } from '../polling/polling-test'; import { extractAndApplyPluginAnalytics } from './plugin-analytics'; import { findAndLoadPolicy } from '../policy'; import { filterIgnoredIssues } from './policy'; import { IssueData, Issue } from '../snyk-test/legacy'; +import { hasFeatureFlag } from '../feature-flags'; +import { delayNextStep } from '../polling/common'; +import { + convertDepGraph, + convertMapCasing, + convertToCamelCase, + getSelf, +} from './unmanaged/utils'; export async function resolveAndTestFacts( ecosystem: Ecosystem, @@ -16,6 +38,194 @@ export async function resolveAndTestFacts( [dir: string]: ScanResult[]; }, options: Options & PolicyOptions, +): Promise<[TestResult[], string[]]> { + const unmanagedDepsOverride = process.env.USE_UNMANAGED_DEPS; + + const featureFlagEnabled = await hasFeatureFlag( + 'snykNewUnmanagedTest', + options, + ); + + return featureFlagEnabled || unmanagedDepsOverride + ? resolveAndTestFactsUnmanagedDeps(scans, options) + : resolveAndTestFactsRegistry(ecosystem, scans, options); +} + +async function submitHashes( + hashes: FileHashes, + orgId: string, +): Promise { + const response: CreateDepGraphResponse = await createDepGraph(hashes, orgId); + + return response.data.id; +} + +async function pollDepGraph(id: string, orgId: string): Promise { + let attempts = 0; + const maxAttempts = 50; + while (attempts < maxAttempts) { + try { + const response = await getDepGraph(id, orgId); + return response.data.attributes; + } catch (e) { + await delayNextStep(attempts, maxAttempts, 1000); + attempts++; + } + } + + return Promise.reject('Failed to get DepGraph'); +} + +async function fetchIssues( + start_time, + dep_graph_data, + component_details, + orgId: string, +) { + const response: GetIssuesResponse = await getIssues( + { + dep_graph: dep_graph_data, + start_time, + component_details, + }, + orgId, + ); + + const issues = response.data.result.issues.map((issue) => { + const converted = convertToCamelCase(issue); + converted.fixInfo = convertToCamelCase(converted.fixInfo); + return converted; + }); + + const issuesData = convertMapCasing<{ + [issueId: string]: IssueData; + }>(response.data.result.issues_data); + + const depGraphData = convertDepGraph(response.data.result.dep_graph); + + const dependencyCount = response.data.result.dep_graph.graph.nodes.find( + (graphNode) => { + return graphNode.node_id === 'root-node'; + }, + )?.deps?.length; + + const depsFilePaths = response.data.result.deps_file_paths; + + const fileSignaturesDetails = convertMapCasing( + response.data.result.file_signatures_details, + ); + + return { + issues, + issuesData, + depGraphData, + dependencyCount, + depsFilePaths, + fileSignaturesDetails, + }; +} + +export async function resolveAndTestFactsUnmanagedDeps( + scans: { + [dir: string]: ScanResult[]; + }, + options: Options & PolicyOptions, +): Promise<[TestResult[], string[]]> { + const results: any[] = []; + const errors: string[] = []; + const packageManager = 'Unmanaged (C/C++)'; + + let orgId = options.org || ''; + + if (orgId === '') { + const self = await getSelf(); + orgId = self.default_org_context; + } + + for (const [path, scanResults] of Object.entries(scans)) { + await spinner(`Resolving and Testing fileSignatures in ${path}`); + for (const scanResult of scanResults) { + try { + const id = await submitHashes( + { hashes: scanResult?.facts[0]?.data }, + orgId, + ); + + const { + start_time, + dep_graph_data, + component_details, + } = await pollDepGraph(id, orgId); + + const { + issues, + issuesData, + depGraphData, + dependencyCount, + depsFilePaths, + fileSignaturesDetails, + } = await fetchIssues( + start_time, + dep_graph_data, + component_details, + orgId, + ); + + const issuesMap: Map = new Map(); + issues.forEach((i) => { + issuesMap[i.issueId] = i; + }); + + const vulnerabilities: IssueData[] = []; + for (const issuesDataKey in issuesData) { + const issueData = issuesData[issuesDataKey]; + const pkgCoordinate = `${issuesMap[issuesDataKey]?.pkgName}@${issuesMap[issuesDataKey]?.pkgVersion}`; + issueData.from = [pkgCoordinate]; + issueData.name = pkgCoordinate; + issueData.packageManager = packageManager; + vulnerabilities.push(issueData); + } + + const policy = await findAndLoadPolicy(path, 'cpp', options); + + const [issuesFiltered, issuesDataFiltered] = filterIgnoredIssues( + issues, + issuesData, + policy, + ); + + results.push({ + issues: issuesFiltered, + issuesData: issuesDataFiltered, + depGraphData, + depsFilePaths, + fileSignaturesDetails, + vulnerabilities, + path, + dependencyCount, + packageManager, + }); + } catch (error) { + const hasStatusCodeError = error.code >= 400 && error.code <= 500; + if (hasStatusCodeError) { + errors.push(error.message); + continue; + } + const failedPath = path ? `in ${path}` : '.'; + errors.push(`Could not test dependencies ${failedPath}`); + } + } + } + spinner.clearAll(); + return [results, errors]; +} + +export async function resolveAndTestFactsRegistry( + ecosystem: Ecosystem, + scans: { + [dir: string]: ScanResult[]; + }, + options: Options & PolicyOptions, ): Promise<[TestResult[], string[]]> { const results: any[] = []; const errors: string[] = []; diff --git a/src/lib/ecosystems/types.ts b/src/lib/ecosystems/types.ts index 59e8197265..52225795ce 100644 --- a/src/lib/ecosystems/types.ts +++ b/src/lib/ecosystems/types.ts @@ -63,11 +63,11 @@ interface UpgradePathItem { isDropped?: boolean; } -interface UpgradePath { +export interface UpgradePath { path: UpgradePathItem[]; } -interface FixInfo { +export interface FixInfo { upgradePaths: UpgradePath[]; isPatchable: boolean; nearestFixedInVersion?: string; diff --git a/src/lib/ecosystems/unmanaged/types.ts b/src/lib/ecosystems/unmanaged/types.ts new file mode 100644 index 0000000000..410137bedf --- /dev/null +++ b/src/lib/ecosystems/unmanaged/types.ts @@ -0,0 +1,264 @@ +import { SEVERITY } from '../../snyk-test/common'; +import { PkgInfo } from '@snyk/dep-graph'; +import { UpgradePath, DepsFilePaths } from '../types'; +import { SupportedProjectTypes } from '../../types'; + +export interface HashFormat { + format: number; + data: string; +} + +export interface FileHash { + size: number; + path: string; + hashes_ffm: HashFormat[]; +} + +export interface FileHashes { + hashes: FileHash[]; +} + +export interface LocationResponse { + id: string; + location: string; + type: string; +} + +export interface JsonApi { + version: string; +} + +export interface Links { + self: string; +} + +export interface CreateDepGraphResponse { + data: LocationResponse; + jsonapi: JsonApi; + links: Links; +} + +export interface DepOpenApi { + node_id: string; +} + +interface NodeOpenApi { + node_id: string; + pkg_id: string; + deps: DepOpenApi[]; +} +export interface Details { + artifact: string; + version: string; + author: string; + path: string; + id: string; + url: string; + score: string; + filePaths: string[]; +} + +export interface DetailsOpenApi { + artifact: string; + version: string; + author: string; + path: string; + id: string; + url: string; + score: number; + file_paths: string[]; +} + +export interface ComponentDetails { + [key: string]: Details; +} + +export interface ComponentDetailsOpenApi { + [key: string]: DetailsOpenApi; +} + +export interface GraphOpenApi { + root_node_id: string; + nodes: NodeOpenApi[]; +} + +export interface Pkg { + id: string; + info: PkgInfo; +} + +export interface PkgManager { + name: string; +} + +export interface DepGraphDataOpenAPI { + schema_version: string; + pkg_manager: PkgManager; + pkgs: Pkg[]; + graph: GraphOpenApi; +} + +export interface Attributes { + start_time: number; + dep_graph_data: DepGraphDataOpenAPI; + component_details: ComponentDetailsOpenApi; +} + +export interface IssuesRequestDetails { + artifact: string; + version: string; + author: string; + path: string; + id: string; + url: string; + score: number; + file_paths: string[]; +} + +export interface IssuesRequestComponentDetails { + [key: string]: IssuesRequestDetails; +} + +export interface IssuesRequestDep { + nodeId: string; +} + +export interface IssuesRequestDepOpenApi { + node_id: string; +} + +export interface IssuesRequestNode { + nodeId: string; + pkgId: string; + deps: IssuesRequestDep[]; +} + +export interface IssuesRequestNodeOpenApi { + node_id: string; + pkg_id: string; + deps: IssuesRequestDepOpenApi[]; +} + +export interface IssuesRequestGraph { + rootNodeId: string; + nodes: IssuesRequestNodeOpenApi[]; + component_details: ComponentDetails; +} + +export interface IssuesRequestGraphOpenApi { + root_node_id: string; + nodes: IssuesRequestNodeOpenApi[]; + component_details: ComponentDetailsOpenApi; +} + +export interface IssuesRequestDepGraphDataOpenAPI { + schema_version: string; + pkg_manager: PkgManager; + pkgs: Pkg[]; + graph: IssuesRequestGraphOpenApi; +} + +export interface IssuesRequestAttributes { + start_time: number; + dep_graph: IssuesRequestDepGraphDataOpenAPI; + component_details: IssuesRequestComponentDetails; +} + +export interface Data { + id: string; + type: string; + attributes: Attributes; +} + +export interface FileSignaturesDetailsOpenApi { + [pkgKey: string]: { + confidence: number; + file_paths: string[]; + }; +} + +export interface FixInfoOpenApi { + upgrade_paths: UpgradePath[]; + is_patchable: boolean; + nearest_fixed_in_version?: string; +} + +export interface IssueOpenApi { + pkg_name: string; + pkg_version?: string; + issue_id: string; + fix_info: FixInfoOpenApi; +} + +export interface IssuesDataOpenApi { + [issueId: string]: IssueDataOpenApi; +} + +export interface GetDepGraphResponse { + data: Data; + jsonapi: JsonApi; + links: Links; +} + +export interface IssuesResponseDataResult { + start_time: string; + issues: IssueOpenApi[]; + issues_data: IssuesDataOpenApi; + dep_graph: DepGraphDataOpenAPI; + deps_file_paths: DepsFilePaths; + file_signatures_details: FileSignaturesDetailsOpenApi; + type: string; +} + +export interface IssuesResponseData { + id: string; + result: IssuesResponseDataResult; +} + +export interface GetIssuesResponse { + jsonapi: JsonApi; + links: Links; + data: IssuesResponseData; +} + +export interface GetDepGraphResponse { + data: Data; + jsonapi: JsonApi; + links: Links; +} + +interface PatchOpenApi { + version: string; + id: string; + urls: string[]; + modification_time: string; +} + +export interface IssueDataOpenApi { + id: string; + package_name: string; + version: string; + module_name?: string; + below: string; // Vulnerable below version + semver: { + vulnerable: string | string[]; + vulnerable_hashes?: string[]; + vulnerable_by_distro?: { + [distro_name_and_version: string]: string[]; + }; + }; + patches: PatchOpenApi[]; + is_new: boolean; + description: string; + title: string; + severity: SEVERITY; + fixed_in: string[]; + legal_instructions?: string; + package_manager?: SupportedProjectTypes; + from?: string[]; + name?: string; + publication_time?: string; + creation_time?: string; + cvsSv3?: string; + credit?: string[]; +} diff --git a/src/lib/ecosystems/unmanaged/utils.ts b/src/lib/ecosystems/unmanaged/utils.ts new file mode 100644 index 0000000000..e0812e9706 --- /dev/null +++ b/src/lib/ecosystems/unmanaged/utils.ts @@ -0,0 +1,80 @@ +import * as camelCase from 'lodash.camelcase'; +import { DepGraphData } from '@snyk/dep-graph'; +import { GraphNode } from '@snyk/dep-graph/dist/core/types'; +import { getAuthHeader } from '../../api-token'; +import { isCI } from '../../is-ci'; +import { makeRequest } from '../../request'; +import config from '../../config'; + +function mapKey(object, iteratee) { + object = Object(object); + const result = {}; + + Object.keys(object).forEach((key) => { + const value = object[key]; + result[iteratee(value, key, object)] = value; + }); + return result; +} + +export function convertToCamelCase(obj: any): T { + return mapKey(obj as Object, (_, key) => camelCase(key)) as any; +} + +export function convertMapCasing(obj: any): T { + const newObj = {} as T; + + for (const [key, data] of Object.entries(obj)) { + newObj[key] = convertToCamelCase(data); + } + return newObj; +} + +export function convertObjectArrayCasing(arr: any[]): T[] { + return arr.map((item) => convertToCamelCase(item)); +} + +export function convertDepGraph(depGraphOpenApi: T) { + const depGraph: DepGraphData = convertToCamelCase(depGraphOpenApi); + depGraph.graph = convertToCamelCase(depGraph.graph); + const nodes: GraphNode[] = depGraph.graph.nodes.map((graphNode) => { + const node: GraphNode = convertToCamelCase(graphNode); + node.deps = node.deps.map((dep) => convertToCamelCase(dep)); + return node; + }); + + depGraph.graph.nodes = nodes; + return depGraph; +} + +export function getSelf() { + return makeSelfRequest().then((res: any) => { + const response = JSON.parse(res.body); + return response?.data?.attributes; + }); +} + +export function makeSelfRequest() { + const payload = { + method: 'GET', + url: `${config.API_REST_URL}/self?version=2022-08-12~experimental`, + json: true, + headers: { + 'x-is-ci': isCI(), + authorization: getAuthHeader(), + }, + }; + + return new Promise((resolve, reject) => { + makeRequest(payload, (error, res, body) => { + if (error) { + return reject(error); + } + + resolve({ + res, + body, + }); + }); + }); +} diff --git a/src/lib/polling/polling-test.ts b/src/lib/polling/polling-test.ts index cd7efe4db6..e98b161128 100644 --- a/src/lib/polling/polling-test.ts +++ b/src/lib/polling/polling-test.ts @@ -6,10 +6,92 @@ import { Options } from '../types'; import { assembleQueryString } from '../snyk-test/common'; import { getAuthHeader } from '../api-token'; import { ScanResult } from '../ecosystems/types'; +import { + CreateDepGraphResponse, + FileHashes, + GetDepGraphResponse, + GetIssuesResponse, + IssuesRequestAttributes, +} from '../ecosystems/unmanaged/types'; import { ResolveAndTestFactsResponse } from './types'; import { delayNextStep, handleProcessingStatus } from './common'; import { TestDependenciesResult } from '../snyk-test/legacy'; +import { sleep } from '../common'; + +export async function getIssues( + issuesRequestAttributes: IssuesRequestAttributes, + orgId: string, +): Promise { + const payload = { + method: 'POST', + url: `${config.API_REST_URL}/orgs/${orgId}/unmanaged_ecosystem/issues?version=2022-06-29~experimental`, + json: true, + headers: { + 'Content-Type': 'application/vnd.api+json', + 'x-is-ci': isCI(), + authorization: getAuthHeader(), + }, + body: issuesRequestAttributes, + }; + + const result = await makeRequest(payload); + return JSON.parse(result.toString()); +} + +export async function getDepGraph( + id: string, + orgId: string, +): Promise { + const payload = { + method: 'GET', + url: `${config.API_REST_URL}/orgs/${orgId}/unmanaged_ecosystem/depgraphs/${id}?version=2022-05-23~experimental`, + json: true, + headers: { + 'Content-Type': 'application/vnd.api+json', + 'x-is-ci': isCI(), + authorization: getAuthHeader(), + }, + }; + + const maxWaitingTimeMs = 30000; + const pollIntervalMs = 5000; + let waitingTimeMs = pollIntervalMs; + let result = {} as GetDepGraphResponse; + while (waitingTimeMs <= maxWaitingTimeMs) { + try { + await sleep(waitingTimeMs); + result = await makeRequest(payload); + break; + } catch (e) { + if (waitingTimeMs < maxWaitingTimeMs) { + waitingTimeMs += pollIntervalMs; + } else { + throw e; + } + } + } + return JSON.parse(result.toString()); +} + +export async function createDepGraph( + hashes: FileHashes, + orgId: string, +): Promise { + const payload = { + method: 'POST', + url: `${config.API_REST_URL}/orgs/${orgId}/unmanaged_ecosystem/depgraphs?version=2022-05-23~experimental`, + json: true, + headers: { + 'Content-Type': 'application/vnd.api+json', + 'x-is-ci': isCI(), + authorization: getAuthHeader(), + }, + body: hashes, + }; + const result = await makeRequest(payload); + return JSON.parse(result.toString()); +} export async function requestTestPollingToken( options: Options, diff --git a/src/lib/snyk-test/legacy.ts b/src/lib/snyk-test/legacy.ts index f53c9f0be1..43450643e3 100644 --- a/src/lib/snyk-test/legacy.ts +++ b/src/lib/snyk-test/legacy.ts @@ -14,7 +14,7 @@ interface Pkg { version?: string; } -interface Patch { +export interface Patch { version: string; id: string; urls: string[]; diff --git a/test/jest/unit/lib/ecosystems/fixtures/create-dep-graph-response.ts b/test/jest/unit/lib/ecosystems/fixtures/create-dep-graph-response.ts new file mode 100644 index 0000000000..3731095763 --- /dev/null +++ b/test/jest/unit/lib/ecosystems/fixtures/create-dep-graph-response.ts @@ -0,0 +1,8 @@ +import {LocationResponse} from "../../../../../../src/lib/ecosystems/unmanaged/types"; + +export const createDepgraphResponse = { + id: '53b2fa4d-3e2a-491e-a73e-c4dafcb0ec6f', + location: + '/rest/unmanaged_ecosystem/depgraphs/53b2fa4d-3e2a-491e-a73e-c4dafcb0ec6f?version=2022-05-23~experimental', + type: 'Location', +} as LocationResponse; \ No newline at end of file diff --git a/test/jest/unit/lib/ecosystems/fixtures/dep-graph-open-api.ts b/test/jest/unit/lib/ecosystems/fixtures/dep-graph-open-api.ts new file mode 100644 index 0000000000..33f1b7fd39 --- /dev/null +++ b/test/jest/unit/lib/ecosystems/fixtures/dep-graph-open-api.ts @@ -0,0 +1,69 @@ +import { + ComponentDetailsOpenApi, + DepGraphDataOpenAPI, + GraphOpenApi, + PkgManager +} from "../../../../../../src/lib/ecosystems/unmanaged/types"; + +const componentDetails: ComponentDetailsOpenApi = { + 'http://cdn.kernel.org/pub/linux/utils/net/iproute2/iproute2-4.2.0.tar.gz@4.2.0': { + artifact: 'iproute2', + version: '4.2.0', + author: 'iproute2_project', + path: 'deps/iproute2-4.2.0', + id: '15292136508eb4f383337eb200000000', + url: + 'http://cdn.kernel.org/pub/linux/utils/net/iproute2/iproute2-4.2.0.tar.gz', + score: 1, + file_paths: [ + 'deps/iproute2-4.2.0/COPYING', + 'deps/iproute2-4.2.0/Makefile', + 'deps/iproute2-4.2.0/README', + 'deps/iproute2-4.2.0/README.decnet', + ], + }, +}; + +const graph: GraphOpenApi = { + root_node_id: 'root-node@0.0.0', + nodes: [ + { + node_id: 'root-node', + pkg_id: 'root-node@0.0.0', + deps: [ + { + node_id: 'https://github.com|nih-at/libzip@1.8.0', + }, + ], + }, + { + node_id: 'https://github.com|nih-at/libzip@1.8.0', + pkg_id: 'https://github.com|nih-at/libzip@1.8.0', + deps: [], + }, + ], +}; + +const pkg_manager: PkgManager = { name: 'cpp' }; + +export const depGraphDataOpenAPI: DepGraphDataOpenAPI = { + schema_version: '1.2.0', + pkg_manager: pkg_manager, + pkgs: [ + { + id: 'root-node@0.0.0', + info: { + name: 'root-node', + version: '0.0.0', + }, + }, + { + id: 'https://github.com|nih-at/libzip@1.8.0', + info: { + name: 'https://github.com|nih-at/libzip', + version: '1.8.0', + }, + }, + ], + graph: graph, +}; diff --git a/test/jest/unit/lib/ecosystems/fixtures/expected-test-result-new-impl.ts b/test/jest/unit/lib/ecosystems/fixtures/expected-test-result-new-impl.ts new file mode 100644 index 0000000000..c417551bae --- /dev/null +++ b/test/jest/unit/lib/ecosystems/fixtures/expected-test-result-new-impl.ts @@ -0,0 +1,153 @@ +import { TestResult } from '../../../../../../src/lib/ecosystems/types'; +import {SEVERITY} from "@snyk/fix/dist/types"; + +const expectedDescription = `## Overview + +Affected versions of this package are vulnerable to Symlink Attack cpio, as used in build 2007.05.10, 2010.07.28, and possibly other versions, allows remote attackers to overwrite arbitrary files via a symlink within an RPM package archive. +## Remediation +There is no fixed version for \`cpio\`. +## References +- [Support.novell.com](http://support.novell.com/security/cve/CVE-2010-4226.html) +`; + +export const expectedTestResult = [ + { + depGraphData: { + graph: { + nodes: [ + { + deps: [ + { + nodeId: 'https://github.com|nih-at/libzip@1.8.0', + }, + ], + nodeId: 'root-node', + pkgId: 'root-node@0.0.0', + }, + { + deps: [], + nodeId: 'https://github.com|nih-at/libzip@1.8.0', + pkgId: 'https://github.com|nih-at/libzip@1.8.0', + }, + ], + rootNodeId: 'root-node@0.0.0', + }, + pkgManager: { + name: 'cpp', + }, + pkgs: [ + { + id: 'root-node@0.0.0', + info: { + name: 'root-node', + version: '0.0.0', + }, + }, + { + id: 'https://github.com|nih-at/libzip@1.8.0', + info: { + name: 'https://github.com|nih-at/libzip', + version: '1.8.0', + }, + }, + ], + schemaVersion: '1.2.0', + }, + dependencyCount: 1, + depsFilePaths: { + "http://github.com/nmoinvaz/minizip/archive/1.1.tar.gz@1.1": [ + "deps/zlib-1.2.11.1/contrib/minizip/Makefile.am", + "deps/zlib-1.2.11.1/contrib/minizip/MiniZip64_Changes.txt", + "deps/zlib-1.2.11.1/contrib/minizip/MiniZip64_info.txt", + "deps/zlib-1.2.11.1/contrib/minizip/configure.ac", + "deps/zlib-1.2.11.1/contrib/minizip/crypt.h", + "deps/zlib-1.2.11.1/contrib/minizip/ioapi.c", + "deps/zlib-1.2.11.1/contrib/minizip/ioapi.h", + "deps/zlib-1.2.11.1/contrib/minizip/iowin32.c", + "deps/zlib-1.2.11.1/contrib/minizip/iowin32.h", + ], + "https://thekelleys.org.uk|dnsmasq@2.80": [ + "deps/dnsmasq-2.80/Android.mk", + "deps/dnsmasq-2.80/CHANGELOG", + "deps/dnsmasq-2.80/CHANGELOG.archive", + "deps/dnsmasq-2.80/COPYING", + "deps/dnsmasq-2.80/COPYING-v3", + "deps/dnsmasq-2.80/FAQ", + "deps/dnsmasq-2.80/Makefile", + ], + }, + "fileSignaturesDetails": { + "https://thekelleys.org.uk|dnsmasq@2.80": { + "confidence": 1, + "filePaths": [ + "deps/dnsmasq-2.80/Android.mk", + "deps/dnsmasq-2.80/CHANGELOG", + "deps/dnsmasq-2.80/CHANGELOG.archive", + "deps/dnsmasq-2.80/COPYING", + "deps/dnsmasq-2.80/COPYING-v3", + "deps/dnsmasq-2.80/FAQ", + "deps/dnsmasq-2.80/Makefile", + "deps/dnsmasq-2.80/VERSION", + ], + }, + }, + issues: [ + { + fixInfo: { + isPatchable: false, + nearestFixedInVersion: '', + upgradePaths: [], + }, + issueId: 'SNYK-UNMANAGED-CPIO-2319543', + pkgName: 'https://ftp.gnu.org|cpio', + pkgVersion: '2.12', + }, + ], + issuesData: { + 'SNYK-UNMANAGED-CPIO-2319543': { + id: 'SNYK-UNMANAGED-CPIO-2319543', + packageName: 'cpio', + version: '', + below: '', + semver: { + "vulnerable": [ + "[0,]" + ] + }, + patches: [], + isNew: false, + description: expectedDescription, + title: 'Symlink Attack', + severity: "medium", + fixedIn: [], + packageManager: "Unmanaged (C/C++)", + from: ['https://ftp.gnu.org|cpio@2.12'], + name: 'https://ftp.gnu.org|cpio@2.12', + }, + }, + packageManager: 'Unmanaged (C/C++)', + path: 'path', + vulnerabilities: [ + { + below: '', + description: expectedDescription, + fixedIn: [], + from: ['https://ftp.gnu.org|cpio@2.12'], + id: 'SNYK-UNMANAGED-CPIO-2319543', + isNew: false, + name: 'https://ftp.gnu.org|cpio@2.12', + packageManager: 'Unmanaged (C/C++)', + packageName: 'cpio', + patches: [], + severity: 'medium', + title: 'Symlink Attack', + version: '', + semver: { + "vulnerable": [ + "[0,]" + ] + }, + }, + ], + }, +]; \ No newline at end of file diff --git a/test/jest/unit/lib/ecosystems/fixtures/get-dep-graph-response.ts b/test/jest/unit/lib/ecosystems/fixtures/get-dep-graph-response.ts new file mode 100644 index 0000000000..38a94bd345 --- /dev/null +++ b/test/jest/unit/lib/ecosystems/fixtures/get-dep-graph-response.ts @@ -0,0 +1,16 @@ +import {Attributes, ComponentDetailsOpenApi, Data} from "../../../../../../src/lib/ecosystems/unmanaged/types"; +import {depGraphDataOpenAPI} from "./dep-graph-open-api"; + +const componentDetailsOpenApi: ComponentDetailsOpenApi = {}; + +const attributes: Attributes = { + start_time: 1660137910316, + dep_graph_data: depGraphDataOpenAPI, + component_details: componentDetailsOpenApi, +}; + +export const getDepGraphResponse: Data = { + id: '1234', + type: 'depgraphs', + attributes: attributes, +} diff --git a/test/jest/unit/lib/ecosystems/fixtures/issues-response.ts b/test/jest/unit/lib/ecosystems/fixtures/issues-response.ts new file mode 100644 index 0000000000..26158f4d0d --- /dev/null +++ b/test/jest/unit/lib/ecosystems/fixtures/issues-response.ts @@ -0,0 +1,95 @@ +import { + FileSignaturesDetailsOpenApi, FixInfoOpenApi, + IssueDataOpenApi, IssueOpenApi, + IssuesDataOpenApi, IssuesResponseData, IssuesResponseDataResult +} from "../../../../../../src/lib/ecosystems/unmanaged/types"; +import {DepsFilePaths} from "snyk-cpp-plugin/dist/types"; +import {SEVERITY} from "../../../../../../src/lib/snyk-test/common"; +import {depGraphDataOpenAPI} from "./dep-graph-open-api"; + +const fileSignaturesDetailsOpenApi: FileSignaturesDetailsOpenApi = { + "https://thekelleys.org.uk|dnsmasq@2.80": { + "confidence": 1, + "file_paths": [ + "deps/dnsmasq-2.80/Android.mk", + "deps/dnsmasq-2.80/CHANGELOG", + "deps/dnsmasq-2.80/CHANGELOG.archive", + "deps/dnsmasq-2.80/COPYING", + "deps/dnsmasq-2.80/COPYING-v3", + "deps/dnsmasq-2.80/FAQ", + "deps/dnsmasq-2.80/Makefile", + "deps/dnsmasq-2.80/VERSION", + ] + } +}; + +const depsFilePaths: DepsFilePaths = { + "https://thekelleys.org.uk|dnsmasq@2.80": [ + "deps/dnsmasq-2.80/Android.mk", + "deps/dnsmasq-2.80/CHANGELOG", + "deps/dnsmasq-2.80/CHANGELOG.archive", + "deps/dnsmasq-2.80/COPYING", + "deps/dnsmasq-2.80/COPYING-v3", + "deps/dnsmasq-2.80/FAQ", + "deps/dnsmasq-2.80/Makefile", + ], + "http://github.com/nmoinvaz/minizip/archive/1.1.tar.gz@1.1": [ + "deps/zlib-1.2.11.1/contrib/minizip/Makefile.am", + "deps/zlib-1.2.11.1/contrib/minizip/MiniZip64_Changes.txt", + "deps/zlib-1.2.11.1/contrib/minizip/MiniZip64_info.txt", + "deps/zlib-1.2.11.1/contrib/minizip/configure.ac", + "deps/zlib-1.2.11.1/contrib/minizip/crypt.h", + "deps/zlib-1.2.11.1/contrib/minizip/ioapi.c", + "deps/zlib-1.2.11.1/contrib/minizip/ioapi.h", + "deps/zlib-1.2.11.1/contrib/minizip/iowin32.c", + "deps/zlib-1.2.11.1/contrib/minizip/iowin32.h", + ] +}; + +const issueDataOpenApi: IssueDataOpenApi = { + id: 'SNYK-UNMANAGED-CPIO-2319543', + package_name: 'cpio', + version: '', + below: '', + semver: { + vulnerable: ['[0,]'], + }, + patches: [], + is_new: false, + description: + '## Overview\n\nAffected versions of this package are vulnerable to Symlink Attack cpio, as used in build 2007.05.10, 2010.07.28, and possibly other versions, allows remote attackers to overwrite arbitrary files via a symlink within an RPM package archive.\n## Remediation\nThere is no fixed version for `cpio`.\n## References\n- [Support.novell.com](http://support.novell.com/security/cve/CVE-2010-4226.html)\n', + title: 'Symlink Attack', + severity: SEVERITY.MEDIUM, + fixed_in: [], + package_manager: 'Unmanaged (C/C++)', + from: [], + name: '', +}; + +const issuesDataOpenApi: IssuesDataOpenApi = { + 'SNYK-UNMANAGED-CPIO-2319543': issueDataOpenApi, +}; + +const fixInfoOpenApi: FixInfoOpenApi = { + upgrade_paths: [], + nearest_fixed_in_version: '', + is_patchable: false, +}; +const issueOpenApi: IssueOpenApi = { + pkg_name: 'https://ftp.gnu.org|cpio', + issue_id: 'SNYK-UNMANAGED-CPIO-2319543', + pkg_version: '2.12', + fix_info: fixInfoOpenApi, +}; +const issuesOpenApi: IssueOpenApi[] = [issueOpenApi]; +const result: IssuesResponseDataResult = { + start_time: '1659598771039', + issues: issuesOpenApi, + issues_data: issuesDataOpenApi, + dep_graph: depGraphDataOpenAPI, + deps_file_paths: depsFilePaths, + file_signatures_details: fileSignaturesDetailsOpenApi, + type: '', +}; + +export const issuesResponseData: IssuesResponseData = { id: '', result: result }; diff --git a/test/jest/unit/lib/ecosystems/resolve-test-facts.spec.ts b/test/jest/unit/lib/ecosystems/resolve-test-facts.spec.ts index b93c6afe2d..7314e01553 100644 --- a/test/jest/unit/lib/ecosystems/resolve-test-facts.spec.ts +++ b/test/jest/unit/lib/ecosystems/resolve-test-facts.spec.ts @@ -1,10 +1,34 @@ import { Options } from '../../../../../src/lib/types'; import * as pollingTest from '../../../../../src/lib/polling/polling-test'; +import * as featureFlags from '../../../../../src/lib/feature-flags/index'; +import * as common from '../../../../../src/lib/polling/common'; import * as promise from '../../../../../src/lib/request/promise'; import { depGraphData, scanResults } from './fixtures/'; import { resolveAndTestFacts } from '../../../../../src/lib/ecosystems/resolve-test-facts'; import * as pluginAnalytics from '../../../../../src/lib/ecosystems/plugin-analytics'; import * as analytics from '../../../../../src/lib/analytics'; +import { + JsonApi, + Links, + LocationResponse, + Data, + Attributes, + DepGraphDataOpenAPI, + ComponentDetailsOpenApi, + PkgManager, + GraphOpenApi, + IssuesResponseData, + IssueOpenApi, + FixInfoOpenApi, + IssuesDataOpenApi, + FileSignaturesDetailsOpenApi, + IssuesResponseDataResult, +} from '../../../../../src/lib/ecosystems/unmanaged/types'; +import { DepsFilePaths } from 'snyk-cpp-plugin/dist/types'; +import { issuesResponseData } from './fixtures/issues-response'; +import { expectedTestResult } from './fixtures/expected-test-result-new-impl'; +import { createDepgraphResponse } from './fixtures/create-dep-graph-response'; +import { getDepGraphResponse } from './fixtures/get-dep-graph-response'; describe('resolve and test facts', () => { afterEach(() => jest.restoreAllMocks()); @@ -18,6 +42,10 @@ describe('resolve and test facts', () => { }; it('failing to resolve and test file-signatures fact for c/c++ projects', async () => { + const hasFeatureFlag: boolean | undefined = false; + const hasFeatureFlagSpy = jest.spyOn(featureFlags, 'hasFeatureFlag'); + hasFeatureFlagSpy.mockResolvedValueOnce(hasFeatureFlag); + const requestTestPollingTokenSpy = jest.spyOn( pollingTest, 'requestTestPollingToken', @@ -27,6 +55,12 @@ describe('resolve and test facts', () => { 'pollingTestWithTokenUntilDone', ); + const createDepGraphSpy = jest.spyOn(pollingTest, 'createDepGraph'); + + const getDepGraphSpy = jest.spyOn(pollingTest, 'getDepGraph'); + + const getIssuesSpy = jest.spyOn(pollingTest, 'getIssues'); + requestTestPollingTokenSpy.mockResolvedValueOnce({ token, status: 'ERROR', @@ -39,6 +73,73 @@ describe('resolve and test facts', () => { 'Internal error (reference: eb9ab16c-1d33-4586-bf99-ef30c144d1f1)', }); + const links: Links = { self: '' }; + const jsonApi: JsonApi = { version: '' }; + const data: LocationResponse = { id: '1234', location: '', type: '' }; + + createDepGraphSpy.mockResolvedValueOnce({ + data: data, + jsonapi: jsonApi, + links: links, + }); + + const graph: GraphOpenApi = { + root_node_id: '', + nodes: [], + }; + const pkg_manager: PkgManager = { name: '' }; + const componentDetailsOpenApi: ComponentDetailsOpenApi = {}; + const depGraphDataOpenAPI: DepGraphDataOpenAPI = { + schema_version: '', + pkg_manager: pkg_manager, + pkgs: [], + graph: graph, + }; + const attributes: Attributes = { + start_time: 0, + dep_graph_data: depGraphDataOpenAPI, + component_details: componentDetailsOpenApi, + }; + const getResponseData: Data = { id: '', type: '', attributes: attributes }; + + getDepGraphSpy.mockResolvedValueOnce({ + data: getResponseData, + jsonapi: jsonApi, + links: links, + }); + + const fileSignaturesDetailsOpenApi: FileSignaturesDetailsOpenApi = {}; + const depsFilePaths: DepsFilePaths = {}; + const issuesDataOpenApi: IssuesDataOpenApi = {}; + const fixInfoOpenApi: FixInfoOpenApi = { + upgrade_paths: [], + nearest_fixed_in_version: '', + is_patchable: false, + }; + const issueOpenApi: IssueOpenApi = { + pkg_name: '', + issue_id: '', + pkg_version: '', + fix_info: fixInfoOpenApi, + }; + const issuesOpenApi: IssueOpenApi[] = [issueOpenApi]; + const result: IssuesResponseDataResult = { + start_time: '', + issues: issuesOpenApi, + issues_data: issuesDataOpenApi, + dep_graph: depGraphDataOpenAPI, + deps_file_paths: depsFilePaths, + file_signatures_details: fileSignaturesDetailsOpenApi, + type: '', + }; + const issuesResponseData: IssuesResponseData = { id: '', result: result }; + + getIssuesSpy.mockResolvedValueOnce({ + data: issuesResponseData, + jsonapi: jsonApi, + links: links, + }); + const [testResults, errors] = await resolveAndTestFacts( 'cpp', scanResults, @@ -58,6 +159,10 @@ describe('resolve and test facts', () => { `( 'should handle different file-signatures processing statuses for the testing flow', async ({ actual, expected }) => { + const hasFeatureFlag: boolean | undefined = false; + const hasFeatureFlagSpy = jest.spyOn(featureFlags, 'hasFeatureFlag'); + hasFeatureFlagSpy.mockResolvedValueOnce(hasFeatureFlag); + const requestTestPollingTokenSpy = jest.spyOn( pollingTest, 'requestTestPollingToken', @@ -88,6 +193,10 @@ describe('resolve and test facts', () => { ); it('successfully resolving and testing file-signatures fact for c/c++ projects', async () => { + const hasFeatureFlag: boolean | undefined = false; + const hasFeatureFlagSpy = jest.spyOn(featureFlags, 'hasFeatureFlag'); + hasFeatureFlagSpy.mockResolvedValueOnce(hasFeatureFlag); + const resolveAndTestFactsSpy = jest.spyOn( pollingTest, 'requestTestPollingToken', @@ -150,4 +259,124 @@ describe('resolve and test facts', () => { ]); expect(errors).toEqual([]); }); + + it('successfully resolving and testing file-signatures fact for c/c++ projects with new unmanaged service', async () => { + const hasFeatureFlag: boolean | undefined = true; + jest + .spyOn(featureFlags, 'hasFeatureFlag') + .mockResolvedValueOnce(hasFeatureFlag); + + jest.spyOn(common, 'delayNextStep').mockImplementation(); + + jest.spyOn(pollingTest, 'createDepGraph').mockResolvedValueOnce({ + data: createDepgraphResponse, + jsonapi: { version: 'v1.0' } as JsonApi, + links: { self: '' } as Links, + }); + + jest.spyOn(pollingTest, 'getDepGraph').mockResolvedValue({ + data: getDepGraphResponse, + jsonapi: { version: 'v1.0' } as JsonApi, + links: { self: '' } as Links, + }); + + jest.spyOn(pollingTest, 'getIssues').mockResolvedValueOnce({ + data: issuesResponseData, + jsonapi: { version: 'v1.0' } as JsonApi, + links: { self: '' } as Links, + }); + + const [testResults, errors] = await resolveAndTestFacts( + 'cpp', + scanResults, + {} as Options, + ); + + expect(testResults).toEqual(expectedTestResult); + expect(errors).toEqual([]); + }); + + it('failed resolving and testing file-signatures since createDepGraph throws exception with new unmanaged service', async () => { + const hasFeatureFlag: boolean | undefined = true; + jest + .spyOn(featureFlags, 'hasFeatureFlag') + .mockResolvedValueOnce(hasFeatureFlag); + + jest.spyOn(common, 'delayNextStep').mockImplementation(); + + jest.spyOn(pollingTest, 'createDepGraph').mockImplementation(() => { + throw new Error('500'); + }); + + const [testResults, errors] = await resolveAndTestFacts( + 'cpp', + scanResults, + {} as Options, + ); + + expect(testResults).toEqual([]); + expect(errors).toEqual(['Could not test dependencies in path']); + }); + + it('failed resolving and testing file-signatures since getDepGraph throws exception with new unmanaged service', async () => { + const hasFeatureFlag: boolean | undefined = true; + jest + .spyOn(featureFlags, 'hasFeatureFlag') + .mockResolvedValueOnce(hasFeatureFlag); + + jest.spyOn(common, 'delayNextStep').mockImplementation(); + + jest.spyOn(pollingTest, 'createDepGraph').mockResolvedValueOnce({ + data: createDepgraphResponse, + jsonapi: { version: 'v1.0' } as JsonApi, + links: { self: '' } as Links, + }); + + jest.spyOn(pollingTest, 'getDepGraph').mockImplementation(() => { + throw new Error('500'); + }); + + const [testResults, errors] = await resolveAndTestFacts( + 'cpp', + scanResults, + {} as Options, + ); + + expect(testResults).toEqual([]); + expect(errors).toEqual(['Could not test dependencies in path']); + }); + + it('failed resolving and testing file-signatures since getIssues throws exception with new unmanaged service', async () => { + const hasFeatureFlag: boolean | undefined = true; + jest + .spyOn(featureFlags, 'hasFeatureFlag') + .mockResolvedValueOnce(hasFeatureFlag); + + jest.spyOn(common, 'delayNextStep').mockImplementation(); + + jest.spyOn(pollingTest, 'createDepGraph').mockResolvedValueOnce({ + data: createDepgraphResponse, + jsonapi: { version: 'v1.0' } as JsonApi, + links: { self: '' } as Links, + }); + + jest.spyOn(pollingTest, 'getDepGraph').mockResolvedValue({ + data: getDepGraphResponse, + jsonapi: { version: 'v1.0' } as JsonApi, + links: { self: '' } as Links, + }); + + jest.spyOn(pollingTest, 'getIssues').mockImplementation(() => { + throw new Error('500'); + }); + + const [testResults, errors] = await resolveAndTestFacts( + 'cpp', + scanResults, + {} as Options, + ); + + expect(testResults).toEqual([]); + expect(errors).toEqual(['Could not test dependencies in path']); + }); }); From af81397668234e38625724f88fe13bafb0439ff1 Mon Sep 17 00:00:00 2001 From: maxjeffos <44034094+maxjeffos@users.noreply.github.com> Date: Fri, 16 Sep 2022 12:32:37 -0400 Subject: [PATCH 39/55] chore: optmize windows binary CI flow --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6df0bae78c..6970bd9118 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -953,7 +953,6 @@ workflows: - Build (snyk-linux) - Build (snyk-linux-arm64) - Build (snyk-macos) - - Build (snyk-win.exe) - Build (snyk-for-docker-desktop-darwin-x64.tar.gz) - Build (snyk-for-docker-desktop-darwin-arm64.tar.gz) - Build (docker-mac-signed-bundle.tar.gz) From 8890fb36c9831fe182f6d3c15eb7a8af172717c3 Mon Sep 17 00:00:00 2001 From: Ofek Atar Date: Tue, 13 Sep 2022 18:56:01 +0300 Subject: [PATCH 40/55] chore: Create IaC smoke tests for experimental test --- .github/CODEOWNERS | 3 + .github/workflows/iac-smoke-tests-pulls.yml | 92 +++++++++++++++++++++ .github/workflows/iac-smoke-tests.yml | 67 +++++++++++++++ package.json | 3 +- test/smoke/iac/README.md | 39 +++++++++ test/smoke/iac/test.spec.ts | 28 +++++++ 6 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/iac-smoke-tests-pulls.yml create mode 100644 .github/workflows/iac-smoke-tests.yml create mode 100644 test/smoke/iac/README.md create mode 100644 test/smoke/iac/test.spec.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a5268d56c1..acb9bbf235 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -34,6 +34,7 @@ test/fixtures/container-app-vulns/ @snyk/mycelium test/fixtures/container-projects/ @snyk/mycelium @snyk/potion test/fixtures/docker/ @snyk/mycelium @snyk/potion test/fixtures/iac/ @snyk/group-infrastructure-as-code +test/smoke/iac/ @snyk/group-infrastructure-as-code test/smoke/spec/iac/ @snyk/group-infrastructure-as-code test/smoke/spec/snyk_code_spec.sh @snyk/zenith test/smoke/spec/snyk_basic_spec.sh @snyk/hammer @@ -70,6 +71,8 @@ test/fixtures/unmanaged-log4j-fixture @snyk/tundra test/jest/acceptance/snyk-log4shell/log4shell-detection.spec.ts @snyk/tundra test/jest/acceptance/snyk-test/app-vuln-container-project.spec.ts @snyk/mycelium /.github @snyk/hammer +/.github/workflows/iac-smoke-tests.yml @snyk/group-infrastructure-as-code +/.github/workflows/iac-smoke-tests-pulls.yml @snyk/group-infrastructure-as-code # tap tests ownership test/tap/cli-monitor/ @snyk/snyk-open-source diff --git a/.github/workflows/iac-smoke-tests-pulls.yml b/.github/workflows/iac-smoke-tests-pulls.yml new file mode 100644 index 0000000000..44db795c0c --- /dev/null +++ b/.github/workflows/iac-smoke-tests-pulls.yml @@ -0,0 +1,92 @@ +name: Infrastructure as Code Smoke Tests (Pull Requests) + +on: + pull_request: + branches: [master] + +jobs: + check_for_changed_iac_files: + name: Check for changed IaC files + runs-on: ubuntu-latest + outputs: + is_changed: ${{ steps.check_iac_files_changed.outputs.is_changed }} + + steps: + - uses: actions/checkout@v2 + + - name: Install jq + run: | + sudo apt-get install jq + + - name: Parse CODEOWNERS file + id: codeowners + uses: SvanBoxel/codeowners-action@v2.2 + with: + file_match_info: 'true' + path: ./.github/CODEOWNERS + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v29.0.4 + + - name: Get all IaC files + id: get_all_iac_files + run: | + ALL_IAC_FILES=$( + echo ${{ toJSON(steps.codeowners.outputs.filematches) }} | + jq '[ + to_entries[] | + select( + .value.owners | + index("@snyk/group-infrastructure-as-code") + ) | + .key + ]' + ) + + echo "::set-output name=all_iac_files::$( + echo $ALL_IAC_FILES + )" + + - id: check_iac_files_changed + name: Check for changed files owned by IaC + run: | + ALL_IAC_FILES=${{ toJson(steps.get_all_iac_files.outputs.all_iac_files) }} + + CHANGED_FILES=$( + echo ${{ steps.changed-files.outputs.all_changed_files }} | + jq -R 'split(" ")' + ) + + CHANGED_IAC_FILES=$( + echo $CHANGED_FILES | + jq --argjson ALL_IAC_FILES "$ALL_IAC_FILES" '[ + .[] | + . as $changed_file | + select( + $ALL_IAC_FILES | + index($changed_file) + ) + ]' + ) + + CHANGED_IAC_FILES_COUNT=$( + echo $CHANGED_IAC_FILES | jq 'length' + ) + + IS_CHANGED=$( + echo $CHANGED_IAC_FILES_COUNT | jq '. > 0' + ) + + $IS_CHANGED && + echo "Found $CHANGED_IAC_FILES_COUNT changed IaC files: $CHANGED_IAC_FILES"|| + echo "No changed IaC files found!" + + echo "::set-output name=is_changed::$IS_CHANGED" + + run_iac_smoke_tests: + name: Run IaC smoke tests + uses: ./.github/workflows/iac-smoke-tests.yml + needs: check_for_changed_iac_files + if: ${{ needs.check_for_changed_iac_files.outputs.is_changed == 'true' }} + secrets: inherit diff --git a/.github/workflows/iac-smoke-tests.yml b/.github/workflows/iac-smoke-tests.yml new file mode 100644 index 0000000000..d51fbd0a8f --- /dev/null +++ b/.github/workflows/iac-smoke-tests.yml @@ -0,0 +1,67 @@ +name: Infrastructure as Code Smoke Tests + +on: + schedule: + - cron: '0 * * * *' + release: + types: [published] + workflow_call: + +jobs: + run_iac_e2e_tests: + runs-on: ${{ matrix.os }}-latest + strategy: + fail-fast: false + matrix: + os: [ubuntu, macos, windows] + + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.ref }} + + - uses: actions/setup-node@v3 + with: + node-version: 15 + + - name: Install jq on macOS + if: ${{ matrix.os == 'macos' }} + run: | + brew install jq + + - name: Install jq on Windows + if: ${{ matrix.os == 'windows'}} + run: | + iwr -useb get.scoop.sh -outfile 'install-scoop.ps1' + .\install-scoop.ps1 -RunAsAdmin + scoop install jq + + - name: Install jq on Ubuntu + if: ${{ matrix.os == 'ubuntu' }} + run: | + sudo apt-get install jq + + - name: Install dependencies + run: | + npm install + + - name: Build Snyk CLI + run: | + npm run build + + - name: Run IaC smoke tests - non-Windows + if: ${{ matrix.os != 'windows' }} + env: + IAC_SMOKE_TESTS_SNYK_TOKEN: ${{ secrets.IAC_SMOKE_TESTS_SNYK_TOKEN }} + TEST_SNYK_COMMAND: ${{ format('node {0}/dist/cli/index.js', github.workspace) }} + run: | + npm run test:smoke:iac + + - name: Run IaC smoke tests - Windows + if: ${{ matrix.os == 'windows' }} + shell: pwsh + env: + IAC_SMOKE_TESTS_SNYK_TOKEN: ${{ secrets.IAC_SMOKE_TESTS_SNYK_TOKEN }} + TEST_SNYK_COMMAND: ${{ format('node {0}\dist\cli\index.js', github.workspace) }} + run: | + npm run test:smoke:iac diff --git a/package.json b/package.json index a64bd28f7f..7460233883 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,8 @@ "test:unit": "jest --runInBand --testPathPattern '/test(/jest)?/unit/'", "test:acceptance": "jest --runInBand --testPathPattern '/test(/jest)?/acceptance/'", "test:tap": "tap -Rspec --timeout=300 --node-arg=-r --node-arg=ts-node/register test/tap/*.test.* ", - "test:smoke": "./scripts/run-smoke-tests-locally.sh" + "test:smoke": "./scripts/run-smoke-tests-locally.sh", + "test:smoke:iac": "jest --runInBand --testPathPattern '/test/smoke(/jest)?/iac/'" }, "keywords": [ "security", diff --git a/test/smoke/iac/README.md b/test/smoke/iac/README.md new file mode 100644 index 0000000000..77c08a6113 --- /dev/null +++ b/test/smoke/iac/README.md @@ -0,0 +1,39 @@ +# Snyk Infrastructure as Code Smoke Tests + +Design goal is to have a single test suite, aligned with the scope of the Snyk CLI's smoke tests, that can detect if IaC commands do not work properly - before and after it's released. The tests help us incorporate resources and requests made via network calls, to provide better coverage for the end to end flow of these commands. Some examples: + +- Network calls made for fetching org properties, such as feature flags data, custom severities, etc. +- Downloading resources from CDNs, e.g., binary executables, ruleset bundles, etc. + +The tests were written with Jest, and use a Snyk CLI executable either configured in the PATH environment variable, or overrode, using the `TEST_SNYK_COMMAND` environment variable, see more in the 'Notes on the + +# Implementation details and usage + +These smoke tests are written with Jest, using the Snyk CLI executable identified on the runtime environment (See 'Notes on the local run' section below to read on how to override it) + +Spec in this folder is used as a + +1. **"name: Infrastructure as Code Smoke Tests" Github Action** - these run every hour and upon releases. +2. **["Infrastructure as Code Smoke Tests (Pull Requests)"] GitHub Action** - these run for pull requests to the `master` branch which include changes to files owned by group IaC. + +```sh +npm run test:smoke:iac +``` + +### Notes on the local run + +These tests can be executed with the following npm script: + +``` +npm run test:smoke:iac +``` + +Alternatively, they can be executed directly via `jest`, by running: + +``` +npx jest test/smoke/iac/ +``` + +You may specify any executable that will be used by the smoke tests, by configuring the `TEST_SNYK_COMMAND` environment variable. E.g. a local exuctable `TEST_SNYK_COMMAND="./snyk-macos"` or an `TEST_SNYK_COMMAND="npx snyk@1.500.0"` or `TEST_SNYK_COMMAND="node ./dist/cli"` for local execution. + +You may also configure an authentication token with the `SNYK_TOKEN` environment variable, to run the tests with any org and user needed. diff --git a/test/smoke/iac/test.spec.ts b/test/smoke/iac/test.spec.ts new file mode 100644 index 0000000000..0e6253c2f6 --- /dev/null +++ b/test/smoke/iac/test.spec.ts @@ -0,0 +1,28 @@ +import { run } from '../../jest/acceptance/iac/helpers'; + +jest.setTimeout(1_000 * 90); + +describe('snyk iac test --experimental', () => { + beforeAll(async () => { + await login(); + }); + + it('runs successfully and resolves with a non-error exit code', async () => { + // Arrange + const filePath = 'iac/depth_detection/root.tf'; + + // Act + const { stderr, stdout, exitCode } = await run( + `snyk iac test --experimental ${filePath}`, + ); + + // Assert + expect(stdout).toContain('Infrastructure as Code'); + expect(stderr).toBe(''); + expect(exitCode).toBeLessThan(2); + }); + + async function login() { + await run(`snyk auth ${process.env.IAC_SMOKE_TESTS_SNYK_TOKEN}`); + } +}); From 04c00bc9be3001340c20e1ae0f2d96a0ab9ab13d Mon Sep 17 00:00:00 2001 From: Dan Moore Date: Wed, 21 Sep 2022 14:10:24 +0100 Subject: [PATCH 41/55] fix: added check for existing key in loop --- src/lib/ecosystems/resolve-test-facts.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/lib/ecosystems/resolve-test-facts.ts b/src/lib/ecosystems/resolve-test-facts.ts index 91cd787b7c..f3b9a7f384 100644 --- a/src/lib/ecosystems/resolve-test-facts.ts +++ b/src/lib/ecosystems/resolve-test-facts.ts @@ -264,12 +264,14 @@ export async function resolveAndTestFactsRegistry( const vulnerabilities: IssueData[] = []; for (const issuesDataKey in response.issuesData) { - const issueData = response.issuesData[issuesDataKey]; - const pkgCoordinate = `${issuesMap[issuesDataKey].pkgName}@${issuesMap[issuesDataKey].pkgVersion}`; - issueData.from = [pkgCoordinate]; - issueData.name = pkgCoordinate; - issueData.packageManager = packageManager; - vulnerabilities.push(issueData); + if (issuesMap[issuesDataKey]) { + const issueData = response.issuesData[issuesDataKey]; + const pkgCoordinate = `${issuesMap[issuesDataKey].pkgName}@${issuesMap[issuesDataKey].pkgVersion}`; + issueData.from = [pkgCoordinate]; + issueData.name = pkgCoordinate; + issueData.packageManager = packageManager; + vulnerabilities.push(issueData); + } } const dependencyCount = response?.depGraphData?.graph?.nodes?.find( From b5f677075e263bab8d60a37958479927f1bced55 Mon Sep 17 00:00:00 2001 From: David Agrest Date: Wed, 21 Sep 2022 16:34:34 +0300 Subject: [PATCH 42/55] fix: improve cpp-plugin performance on windows --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5261c42041..7fda5bfa7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,7 @@ "rimraf": "^2.6.3", "semver": "^6.0.0", "snyk-config": "4.0.0", - "snyk-cpp-plugin": "2.20.0", + "snyk-cpp-plugin": "2.20.1", "snyk-docker-plugin": "^5.4.3", "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.22.2", @@ -16439,9 +16439,9 @@ } }, "node_modules/snyk-cpp-plugin": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/snyk-cpp-plugin/-/snyk-cpp-plugin-2.20.0.tgz", - "integrity": "sha512-MYsoeQg2JRZ2aLF4IDiWSnRmqV37H+mRDhQ5snTwznIpMi7Jx8hRAgbE3x04ZEKvgSyRCpeFz+lbu8RPQ5/7+w==", + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/snyk-cpp-plugin/-/snyk-cpp-plugin-2.20.1.tgz", + "integrity": "sha512-GwKzyUZJuhm1C4EFxTysj4PNFhFT4QhvTTZSaoHQ/rUQ3n0lR4G2DjvhMoiIXY51WKtvcRGpSV9yetTAtM37tA==", "dependencies": { "@snyk/dep-graph": "^1.19.3", "@types/minimatch": "^3.0.5", @@ -32864,9 +32864,9 @@ } }, "snyk-cpp-plugin": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/snyk-cpp-plugin/-/snyk-cpp-plugin-2.20.0.tgz", - "integrity": "sha512-MYsoeQg2JRZ2aLF4IDiWSnRmqV37H+mRDhQ5snTwznIpMi7Jx8hRAgbE3x04ZEKvgSyRCpeFz+lbu8RPQ5/7+w==", + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/snyk-cpp-plugin/-/snyk-cpp-plugin-2.20.1.tgz", + "integrity": "sha512-GwKzyUZJuhm1C4EFxTysj4PNFhFT4QhvTTZSaoHQ/rUQ3n0lR4G2DjvhMoiIXY51WKtvcRGpSV9yetTAtM37tA==", "requires": { "@snyk/dep-graph": "^1.19.3", "@types/minimatch": "^3.0.5", diff --git a/package.json b/package.json index 7460233883..7b23428733 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "rimraf": "^2.6.3", "semver": "^6.0.0", "snyk-config": "4.0.0", - "snyk-cpp-plugin": "2.20.0", + "snyk-cpp-plugin": "2.20.1", "snyk-docker-plugin": "^5.4.3", "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.22.2", From 51ade80dce2e396e1f3ea20b16d84b0dcfd0db89 Mon Sep 17 00:00:00 2001 From: Ofek Atar Date: Wed, 21 Sep 2022 16:20:27 +0300 Subject: [PATCH 43/55] refactor: Move ignored issues count to scan analytics --- src/lib/formatters/iac-output/text/formatters.ts | 2 +- src/lib/iac/test/v2/scan/results.ts | 2 +- .../fixtures/snyk-iac-test-results-with-suppressions.json | 6 +++--- .../process-results/fixtures/snyk-iac-test-results.json | 7 ++++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/lib/formatters/iac-output/text/formatters.ts b/src/lib/formatters/iac-output/text/formatters.ts index b20b8995d8..26d1e3ed26 100644 --- a/src/lib/formatters/iac-output/text/formatters.ts +++ b/src/lib/formatters/iac-output/text/formatters.ts @@ -106,7 +106,7 @@ export function formatSnykIacTestTestData( const filesWithIssuesCount = countFilesWithIssues(snykIacTestScanResult); const filesWithoutIssuesCount = allFilesCount - filesWithIssuesCount; const ignores = snykIacTestScanResult - ? snykIacTestScanResult.metadata.ignoredCount + ? snykIacTestScanResult.scanAnalytics.ignoredCount : 0; let contextSuppressedIssueCount: number | undefined; diff --git a/src/lib/iac/test/v2/scan/results.ts b/src/lib/iac/test/v2/scan/results.ts index 0a3cc0045b..fee2a75225 100644 --- a/src/lib/iac/test/v2/scan/results.ts +++ b/src/lib/iac/test/v2/scan/results.ts @@ -39,11 +39,11 @@ export interface Results { export interface Metadata { projectName: string; - ignoredCount: number; } export interface ScanAnalytics { suppressedResults?: Record; + ignoredCount: number; } export interface Vulnerability { diff --git a/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results-with-suppressions.json b/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results-with-suppressions.json index 5ae8c7e5c0..8991a90f1c 100644 --- a/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results-with-suppressions.json +++ b/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results-with-suppressions.json @@ -147,14 +147,14 @@ } ], "metadata": { - "projectName": "input-files-for-json-v2", - "ignoredCount": 3 + "projectName": "input-files-for-json-v2" }, "scanAnalytics": { "suppressedResults": { "issue-1": ["resource1", "resource2"], "issue-2": ["resource3"] - } + }, + "ignoredCount": 3 } }, "errors": [ diff --git a/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results.json b/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results.json index 13278ef803..d5743beffe 100644 --- a/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results.json +++ b/test/jest/unit/iac/process-results/fixtures/snyk-iac-test-results.json @@ -147,10 +147,11 @@ } ], "metadata": { - "projectName": "input-files-for-json-v2", - "ignoredCount": 3 + "projectName": "input-files-for-json-v2" }, - "scanAnalytics": {} + "scanAnalytics": { + "ignoredCount": 3 + } }, "errors": [ { From 5231e69d119bc1a0b0c9246efa5f189f4fa44b9d Mon Sep 17 00:00:00 2001 From: Ofek Atar Date: Thu, 22 Sep 2022 15:28:17 +0300 Subject: [PATCH 44/55] chore: Removed IaC smoke tests npm script --- .github/workflows/iac-smoke-tests.yml | 4 ++-- package.json | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/iac-smoke-tests.yml b/.github/workflows/iac-smoke-tests.yml index d51fbd0a8f..5508aed1a6 100644 --- a/.github/workflows/iac-smoke-tests.yml +++ b/.github/workflows/iac-smoke-tests.yml @@ -55,7 +55,7 @@ jobs: IAC_SMOKE_TESTS_SNYK_TOKEN: ${{ secrets.IAC_SMOKE_TESTS_SNYK_TOKEN }} TEST_SNYK_COMMAND: ${{ format('node {0}/dist/cli/index.js', github.workspace) }} run: | - npm run test:smoke:iac + npx jest --runInBand --testPathPattern '/test/smoke(/jest)?/iac/' - name: Run IaC smoke tests - Windows if: ${{ matrix.os == 'windows' }} @@ -64,4 +64,4 @@ jobs: IAC_SMOKE_TESTS_SNYK_TOKEN: ${{ secrets.IAC_SMOKE_TESTS_SNYK_TOKEN }} TEST_SNYK_COMMAND: ${{ format('node {0}\dist\cli\index.js', github.workspace) }} run: | - npm run test:smoke:iac + npx jest --runInBand --testPathPattern '/test/smoke(/jest)?/iac/' diff --git a/package.json b/package.json index 7b23428733..9465c0920a 100644 --- a/package.json +++ b/package.json @@ -43,8 +43,7 @@ "test:unit": "jest --runInBand --testPathPattern '/test(/jest)?/unit/'", "test:acceptance": "jest --runInBand --testPathPattern '/test(/jest)?/acceptance/'", "test:tap": "tap -Rspec --timeout=300 --node-arg=-r --node-arg=ts-node/register test/tap/*.test.* ", - "test:smoke": "./scripts/run-smoke-tests-locally.sh", - "test:smoke:iac": "jest --runInBand --testPathPattern '/test/smoke(/jest)?/iac/'" + "test:smoke": "./scripts/run-smoke-tests-locally.sh" }, "keywords": [ "security", From 17b1273a4f2358ade99bfe14b523bfcc907b0c2f Mon Sep 17 00:00:00 2001 From: jdunsby Date: Fri, 23 Sep 2022 13:19:48 +0100 Subject: [PATCH 45/55] feat: pass snykHttpClient to plugin.inspect --- package-lock.json | 81 ++++++++------------- package.json | 2 +- src/cli/args.ts | 1 + src/lib/module-info/index.ts | 8 +- src/lib/plugins/get-single-plugin-result.ts | 2 + src/lib/request/snyk-http-client.ts | 39 ++++++++++ src/lib/types.ts | 3 +- test/tap/cli-monitor.acceptance.test.ts | 14 ++++ test/tap/cli-test.acceptance.test.ts | 2 + test/tap/cli-test/cli-test.composer.spec.ts | 31 +++++--- test/tap/cli-test/cli-test.elixir.spec.ts | 12 ++- test/tap/cli-test/cli-test.go.spec.ts | 36 +++++++-- test/tap/cli-test/cli-test.maven.spec.ts | 6 ++ test/tap/cli-test/cli-test.nuget.spec.ts | 42 +++++++++-- test/tap/cli-test/cli-test.python.spec.ts | 25 ++++++- 15 files changed, 222 insertions(+), 82 deletions(-) create mode 100644 src/lib/request/snyk-http-client.ts diff --git a/package-lock.json b/package-lock.json index 7fda5bfa7b..0fb1443486 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,7 +68,7 @@ "snyk-cpp-plugin": "2.20.1", "snyk-docker-plugin": "^5.4.3", "snyk-go-plugin": "1.19.2", - "snyk-gradle-plugin": "3.22.2", + "snyk-gradle-plugin": "3.23.0", "snyk-module": "3.1.0", "snyk-mvn-plugin": "2.31.0", "snyk-nodejs-lockfile-parser": "1.38.0", @@ -14321,6 +14321,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -16534,20 +16548,6 @@ "node": ">=10" } }, - "node_modules/snyk-cpp-plugin/node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/snyk-cpp-plugin/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -16839,9 +16839,9 @@ } }, "node_modules/snyk-gradle-plugin": { - "version": "3.22.2", - "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.22.2.tgz", - "integrity": "sha512-5zBsEEq9SrQI59OFAnalZJ5hWCKM/LF/JUa3x8F1HVayqNzjMSIqiNa4d4oleMzHo9Rp6QUih1I1J8nbtpwnHg==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.23.0.tgz", + "integrity": "sha512-cx4frLM6UDdAi8h7XGPBBHNzAFj6mcgYRIwR2ibnE72CgIGx0gGZ7iMhjhlqFHTDgYNliQdAXb3GHB8V/UXFNw==", "dependencies": { "@snyk/cli-interface": "2.11.3", "@snyk/dep-graph": "^1.28.0", @@ -16849,11 +16849,12 @@ "@types/debug": "^4.1.4", "chalk": "^3.0.0", "debug": "^4.1.1", + "p-map": "^4.0.0", "tmp": "0.2.1", "tslib": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=16" } }, "node_modules/snyk-gradle-plugin/node_modules/@snyk/cli-interface": { @@ -20059,19 +20060,6 @@ "node": ">=8" } }, - "packages/snyk-fix/node_modules/p-map": { - "version": "4.0.0", - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "packages/snyk-fix/node_modules/strip-ansi": { "version": "6.0.0", "license": "MIT", @@ -21719,12 +21707,6 @@ "has-flag": { "version": "4.0.0" }, - "p-map": { - "version": "4.0.0", - "requires": { - "aggregate-error": "^3.0.0" - } - }, "strip-ansi": { "version": "6.0.0", "requires": { @@ -31264,6 +31246,14 @@ } } }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "requires": { + "aggregate-error": "^3.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -32932,14 +32922,6 @@ "yallist": "^4.0.0" } }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "requires": { - "aggregate-error": "^3.0.0" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -33178,9 +33160,9 @@ } }, "snyk-gradle-plugin": { - "version": "3.22.2", - "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.22.2.tgz", - "integrity": "sha512-5zBsEEq9SrQI59OFAnalZJ5hWCKM/LF/JUa3x8F1HVayqNzjMSIqiNa4d4oleMzHo9Rp6QUih1I1J8nbtpwnHg==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.23.0.tgz", + "integrity": "sha512-cx4frLM6UDdAi8h7XGPBBHNzAFj6mcgYRIwR2ibnE72CgIGx0gGZ7iMhjhlqFHTDgYNliQdAXb3GHB8V/UXFNw==", "requires": { "@snyk/cli-interface": "2.11.3", "@snyk/dep-graph": "^1.28.0", @@ -33188,6 +33170,7 @@ "@types/debug": "^4.1.4", "chalk": "^3.0.0", "debug": "^4.1.1", + "p-map": "^4.0.0", "tmp": "0.2.1", "tslib": "^2.0.0" }, diff --git a/package.json b/package.json index 7b23428733..334cd16d25 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "snyk-cpp-plugin": "2.20.1", "snyk-docker-plugin": "^5.4.3", "snyk-go-plugin": "1.19.2", - "snyk-gradle-plugin": "3.22.2", + "snyk-gradle-plugin": "3.23.0", "snyk-module": "3.1.0", "snyk-mvn-plugin": "2.31.0", "snyk-nodejs-lockfile-parser": "1.38.0", diff --git a/src/cli/args.ts b/src/cli/args.ts index dde393515c..72a347a75c 100644 --- a/src/cli/args.ts +++ b/src/cli/args.ts @@ -223,6 +223,7 @@ export function args(rawArgv: string[]): Args { 'prune-repeated-subdependencies', 'dry-run', 'sequential', + 'gradle-normalize-deps', ]; for (const dashedArg of argumentsToTransform) { if (argv[dashedArg]) { diff --git a/src/lib/module-info/index.ts b/src/lib/module-info/index.ts index 9b3cc6b2e9..9787261e4a 100644 --- a/src/lib/module-info/index.ts +++ b/src/lib/module-info/index.ts @@ -10,6 +10,7 @@ export function ModuleInfo(plugin, policy) { root, targetFile, options, + snykHttpClient, ): Promise { const pluginOptions = merge( { @@ -19,7 +20,12 @@ export function ModuleInfo(plugin, policy) { ); debug('calling plugin inspect()', { root, targetFile, pluginOptions }); - const info = await plugin.inspect(root, targetFile, pluginOptions); + const info = await plugin.inspect( + root, + targetFile, + pluginOptions, + snykHttpClient, + ); debug('plugin inspect() done'); // attach policy if not provided by plugin diff --git a/src/lib/plugins/get-single-plugin-result.ts b/src/lib/plugins/get-single-plugin-result.ts index 2c5f3e822b..81a905e116 100644 --- a/src/lib/plugins/get-single-plugin-result.ts +++ b/src/lib/plugins/get-single-plugin-result.ts @@ -2,6 +2,7 @@ import plugins = require('.'); import { ModuleInfo } from '../module-info'; import { legacyPlugin as pluginApi } from '@snyk/cli-interface'; import { TestOptions, Options, MonitorOptions } from '../types'; +import { snykHttpClient } from '../request/snyk-http-client'; export async function getSinglePluginResult( root: string, @@ -14,6 +15,7 @@ export async function getSinglePluginResult( root, targetFile || options.file, { ...options }, + snykHttpClient, ); return inspectRes; } diff --git a/src/lib/request/snyk-http-client.ts b/src/lib/request/snyk-http-client.ts new file mode 100644 index 0000000000..c0b7501915 --- /dev/null +++ b/src/lib/request/snyk-http-client.ts @@ -0,0 +1,39 @@ +import * as needle from 'needle'; +import { OutgoingHttpHeaders } from 'http'; +import { NeedleHttpVerbs } from 'needle'; +import { makeRequest } from '../request/index'; +import { getAuthHeader } from '../api-token'; +import config from '../config'; +import { Payload } from '../request/types'; + +interface RequestInfo { + method: NeedleHttpVerbs; + path: string; + body: any; + headers?: OutgoingHttpHeaders; + qs?: {}; + json?: boolean; + timeout?: number; + family?: number; +} + +export async function snykHttpClient( + requestInfo: RequestInfo, +): Promise<{ + res: needle.NeedleResponse; + body: any; +}> { + let { path } = requestInfo; + if (!path.startsWith('/')) path = `/${path}`; + + const payload: Payload = { + ...requestInfo, + url: `${config.API_REST_URL}${path}`, + headers: { + ...requestInfo.headers, + Authorization: getAuthHeader(), + }, + }; + + return makeRequest(payload); +} diff --git a/src/lib/types.ts b/src/lib/types.ts index 6ad8f860fb..3705e27bf4 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -225,7 +225,8 @@ export type SupportedUserReachableFacingCliArgs = | 'sub-project' | 'trust-policies' | 'yarn-workspaces' - | 'maven-aggregate-project'; + | 'maven-aggregate-project' + | 'gradle-normalize-deps'; export enum SupportedCliCommands { version = 'version', diff --git a/test/tap/cli-monitor.acceptance.test.ts b/test/tap/cli-monitor.acceptance.test.ts index 0357a7ef6a..97bec8103a 100644 --- a/test/tap/cli-monitor.acceptance.test.ts +++ b/test/tap/cli-monitor.acceptance.test.ts @@ -41,6 +41,7 @@ import { DepGraphBuilder } from '@snyk/dep-graph'; import * as depGraphLib from '@snyk/dep-graph'; import { getFixturePath } from '../jest/util/getFixturePath'; import { getWorkspacePath } from '../jest/util/getWorkspacePath'; +import { snykHttpClient } from '../../src/lib/request/snyk-http-client'; /* TODO: enable these tests, once we switch from node-tap @@ -927,6 +928,7 @@ if (!isWindows) { packageManager: 'pip', path: 'pip-app', }, + snykHttpClient, ], 'calls python plugin', ); @@ -990,6 +992,7 @@ if (!isWindows) { packageManager: 'pip', path: 'pip-app', }, + snykHttpClient, ], 'calls python plugin', ); @@ -1042,6 +1045,7 @@ if (!isWindows) { file: 'build.gradle', path: 'gradle-app', }, + snykHttpClient, ], 'calls gradle plugin', ); @@ -1111,6 +1115,7 @@ if (!isWindows) { packageManager: 'gradle', path: 'gradle-app', }, + snykHttpClient, ], 'calls gradle plugin', ); @@ -1170,6 +1175,7 @@ if (!isWindows) { packageManager: 'gradle', path: 'gradle-app', }, + snykHttpClient, ], 'calls gradle plugin', ); @@ -1224,6 +1230,7 @@ if (!isWindows) { packageManager: 'gradle', path: 'gradle-app', }, + snykHttpClient, ], 'calls plugin for the 1st path', ); @@ -1239,6 +1246,7 @@ if (!isWindows) { packageManager: 'pip', path: 'pip-app', }, + snykHttpClient, ], 'calls plugin for the 2nd path', ); @@ -1316,6 +1324,7 @@ if (!isWindows) { packageManager: 'gomodules', path: 'golang-gomodules', }, + snykHttpClient, ], 'calls golang plugin', ); @@ -1364,6 +1373,7 @@ if (!isWindows) { packageManager: 'golangdep', path: 'golang-app', }, + snykHttpClient, ], 'calls golang plugin', ); @@ -1412,6 +1422,7 @@ if (!isWindows) { packageManager: 'govendor', path: 'golang-app', }, + snykHttpClient, ], 'calls golang plugin', ); @@ -1458,6 +1469,7 @@ if (!isWindows) { packageManager: 'cocoapods', path: './', }, + snykHttpClient, ], 'calls CocoaPods plugin', ); @@ -1506,6 +1518,7 @@ if (!isWindows) { packageManager: 'cocoapods', path: './', }, + snykHttpClient, ], 'calls CocoaPods plugin', ); @@ -1560,6 +1573,7 @@ if (!isWindows) { packageManager: 'cocoapods', path: './', }, + snykHttpClient, ], 'calls CocoaPods plugin', ); diff --git a/test/tap/cli-test.acceptance.test.ts b/test/tap/cli-test.acceptance.test.ts index faae3db88d..c9960807e7 100644 --- a/test/tap/cli-test.acceptance.test.ts +++ b/test/tap/cli-test.acceptance.test.ts @@ -65,6 +65,7 @@ const after = tap.runOnly ? only : test; // Should be after `process.env` setup. import * as plugins from '../../src/lib/plugins/index'; import * as ecoSystemPlugins from '../../src/lib/ecosystems/plugins'; +import { snykHttpClient } from '../../src/lib/request/snyk-http-client'; /* TODO: enable these tests, once we switch from node-tap @@ -134,6 +135,7 @@ test('Languages', async (t) => { languageTest.tests[testName]( { server, plugins, ecoSystemPlugins, versionNumber, cli }, { chdirWorkspaces }, + snykHttpClient, ), ); server.restore(); diff --git a/test/tap/cli-test/cli-test.composer.spec.ts b/test/tap/cli-test/cli-test.composer.spec.ts index fd9768c827..3572b4662d 100644 --- a/test/tap/cli-test/cli-test.composer.spec.ts +++ b/test/tap/cli-test/cli-test.composer.spec.ts @@ -5,9 +5,11 @@ import { AcceptanceTests } from '../cli-test.acceptance.test'; export const ComposerTests: AcceptanceTests = { language: 'Composer', tests: { - '`test composer-app --file=composer.lock`': (params, utils) => async ( - t, - ) => { + '`test composer-app --file=composer.lock`': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -49,14 +51,17 @@ export const ComposerTests: AcceptanceTests = { path: 'composer-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls composer plugin', ); }, - '`test composer-app` auto-detects composer.lock': (params, utils) => async ( - t, - ) => { + '`test composer-app` auto-detects composer.lock': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -96,14 +101,17 @@ export const ComposerTests: AcceptanceTests = { path: 'composer-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls composer plugin', ); }, - '`test composer-app --file=composer.lock --dev`': (params, utils) => async ( - t, - ) => { + '`test composer-app --file=composer.lock --dev`': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -147,6 +155,7 @@ export const ComposerTests: AcceptanceTests = { path: 'composer-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls composer plugin', ); @@ -155,6 +164,7 @@ export const ComposerTests: AcceptanceTests = { '`test composer-app golang-app nuget-app` auto-detects all three projects': ( params, utils, + snykHttpClient, ) => async (t) => { utils.chdirWorkspaces(); const plugin = { @@ -223,6 +233,7 @@ export const ComposerTests: AcceptanceTests = { path: 'composer-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls composer plugin', ); @@ -240,6 +251,7 @@ export const ComposerTests: AcceptanceTests = { path: 'golang-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls golangdep plugin', ); @@ -257,6 +269,7 @@ export const ComposerTests: AcceptanceTests = { path: 'nuget-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls nuget plugin', ); diff --git a/test/tap/cli-test/cli-test.elixir.spec.ts b/test/tap/cli-test/cli-test.elixir.spec.ts index e30e4d0eec..2c0ba7323c 100644 --- a/test/tap/cli-test/cli-test.elixir.spec.ts +++ b/test/tap/cli-test/cli-test.elixir.spec.ts @@ -5,7 +5,9 @@ import * as depGraphLib from '@snyk/dep-graph'; export const ElixirTests: AcceptanceTests = { language: 'Elixir', tests: { - '`test elixir --file=mix.exs`': (params, utils) => async (t) => { + '`test elixir --file=mix.exs`': (params, utils, snykHttpClient) => async ( + t, + ) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -52,12 +54,17 @@ export const ElixirTests: AcceptanceTests = { path: 'elixir-hex', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls golang plugin', ); }, - '`test elixir-hex` auto-detects hex': (params, utils) => async (t) => { + '`test elixir-hex` auto-detects hex': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -103,6 +110,7 @@ export const ElixirTests: AcceptanceTests = { path: 'elixir-hex', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls elixir-hex plugin', ); diff --git a/test/tap/cli-test/cli-test.go.spec.ts b/test/tap/cli-test/cli-test.go.spec.ts index 22024dd37d..58997114e6 100644 --- a/test/tap/cli-test/cli-test.go.spec.ts +++ b/test/tap/cli-test/cli-test.go.spec.ts @@ -4,7 +4,11 @@ import { AcceptanceTests } from '../cli-test.acceptance.test'; export const GoTests: AcceptanceTests = { language: 'Go', tests: { - '`test golang-gomodules --file=go.mod`': (params, utils) => async (t) => { + '`test golang-gomodules --file=go.mod`': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -51,6 +55,7 @@ export const GoTests: AcceptanceTests = { path: 'golang-gomodules', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls golang plugin', ); @@ -59,6 +64,7 @@ export const GoTests: AcceptanceTests = { '`test golang-app` auto-detects golang-gomodules': ( params, utils, + snykHttpClient, ) => async (t) => { utils.chdirWorkspaces(); const plugin = { @@ -104,12 +110,17 @@ export const GoTests: AcceptanceTests = { path: 'golang-gomodules', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls golang-gomodules plugin', ); }, - '`test golang-app --file=Gopkg.lock`': (params, utils) => async (t) => { + '`test golang-app --file=Gopkg.lock`': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -156,14 +167,17 @@ export const GoTests: AcceptanceTests = { path: 'golang-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls golang plugin', ); }, - '`test golang-app --file=vendor/vendor.json`': (params, utils) => async ( - t, - ) => { + '`test golang-app --file=vendor/vendor.json`': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -210,14 +224,17 @@ export const GoTests: AcceptanceTests = { path: 'golang-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls golang plugin', ); }, - '`test golang-app` auto-detects golang/dep': (params, utils) => async ( - t, - ) => { + '`test golang-app` auto-detects golang/dep': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -262,6 +279,7 @@ export const GoTests: AcceptanceTests = { path: 'golang-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls golang plugin', ); @@ -270,6 +288,7 @@ export const GoTests: AcceptanceTests = { '`test golang-app-govendor` auto-detects govendor': ( params, utils, + snykHttpClient, ) => async (t) => { utils.chdirWorkspaces(); const plugin = { @@ -310,6 +329,7 @@ export const GoTests: AcceptanceTests = { path: 'golang-app-govendor', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls golang plugin', ); diff --git a/test/tap/cli-test/cli-test.maven.spec.ts b/test/tap/cli-test/cli-test.maven.spec.ts index a9d3249dc6..d44ac34a49 100644 --- a/test/tap/cli-test/cli-test.maven.spec.ts +++ b/test/tap/cli-test/cli-test.maven.spec.ts @@ -65,6 +65,7 @@ export const MavenTests: AcceptanceTests = { '`test maven-app-with-jars --file=example.jar` sends package info': ( params, utils, + snykHttpClient, ) => async (t) => { utils.chdirWorkspaces(); const plugin = { @@ -109,6 +110,7 @@ export const MavenTests: AcceptanceTests = { path: 'maven-app-with-jars', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls mvn plugin', ); @@ -117,6 +119,7 @@ export const MavenTests: AcceptanceTests = { '`test maven-app-with-jars --file=example.war` sends package info': ( params, utils, + snykHttpClient, ) => async (t) => { utils.chdirWorkspaces(); const plugin = { @@ -161,6 +164,7 @@ export const MavenTests: AcceptanceTests = { path: 'maven-app-with-jars', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls mvn plugin', ); @@ -169,6 +173,7 @@ export const MavenTests: AcceptanceTests = { '`test maven-app-with-jars --scan-all-unmanaged` sends package info': ( params, utils, + snykHttpClient, ) => async (t) => { utils.chdirWorkspaces(); const plugin = { @@ -211,6 +216,7 @@ export const MavenTests: AcceptanceTests = { showVulnPaths: 'some', scanAllUnmanaged: true, }, + snykHttpClient, ], 'calls mvn plugin', ); diff --git a/test/tap/cli-test/cli-test.nuget.spec.ts b/test/tap/cli-test/cli-test.nuget.spec.ts index 5fb0639953..aeda4cf03c 100644 --- a/test/tap/cli-test/cli-test.nuget.spec.ts +++ b/test/tap/cli-test/cli-test.nuget.spec.ts @@ -27,6 +27,7 @@ export const NugetTests: AcceptanceTests = { '`test nuget-app-2 auto-detects project.assets.json`': ( params, utils, + snykHttpClient, ) => async (t) => { utils.chdirWorkspaces(); const plugin = { @@ -71,6 +72,7 @@ export const NugetTests: AcceptanceTests = { path: 'nuget-app-2', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls nuget plugin', ); @@ -79,6 +81,7 @@ export const NugetTests: AcceptanceTests = { '`test nuget-app-2.1 auto-detects obj/project.assets.json`': ( params, utils, + snykHttpClient, ) => async (t) => { utils.chdirWorkspaces(); const plugin = { @@ -123,6 +126,7 @@ export const NugetTests: AcceptanceTests = { path: 'nuget-app-2.1', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls nuget plugin', ); @@ -131,6 +135,7 @@ export const NugetTests: AcceptanceTests = { '`test nuget-app-4 auto-detects packages.config`': ( params, utils, + snykHttpClient, ) => async (t) => { utils.chdirWorkspaces(); const plugin = { @@ -176,14 +181,17 @@ export const NugetTests: AcceptanceTests = { path: 'nuget-app-4', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls nuget plugin', ); }, - '`test nuget-app --file=project.assets.json`': (params, utils) => async ( - t, - ) => { + '`test nuget-app --file=project.assets.json`': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -230,12 +238,17 @@ export const NugetTests: AcceptanceTests = { path: 'nuget-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls nuget plugin', ); }, - '`test nuget-app --file=packages.config`': (params, utils) => async (t) => { + '`test nuget-app --file=packages.config`': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -282,12 +295,17 @@ export const NugetTests: AcceptanceTests = { path: 'nuget-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls nuget plugin', ); }, - '`test nuget-app --file=project.json`': (params, utils) => async (t) => { + '`test nuget-app --file=project.json`': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -334,6 +352,7 @@ export const NugetTests: AcceptanceTests = { path: 'nuget-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls nuget plugin', ); @@ -342,6 +361,7 @@ export const NugetTests: AcceptanceTests = { '`test paket-app auto-detects paket.dependencies`': ( params, utils, + snykHttpClient, ) => async (t) => { utils.chdirWorkspaces(); const plugin = { @@ -387,6 +407,7 @@ export const NugetTests: AcceptanceTests = { path: 'paket-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls nuget plugin', ); @@ -395,6 +416,7 @@ export const NugetTests: AcceptanceTests = { '`test paket-obj-app auto-detects obj/project.assets.json if exists`': ( params, utils, + snykHttpClient, ) => async (t) => { utils.chdirWorkspaces(); const plugin = { @@ -440,14 +462,17 @@ export const NugetTests: AcceptanceTests = { path: 'paket-obj-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls nuget plugin', ); }, - '`test paket-app --file=paket.dependencies`': (params, utils) => async ( - t, - ) => { + '`test paket-app --file=paket.dependencies`': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -494,6 +519,7 @@ export const NugetTests: AcceptanceTests = { path: 'paket-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls nuget plugin', ); diff --git a/test/tap/cli-test/cli-test.python.spec.ts b/test/tap/cli-test/cli-test.python.spec.ts index fff2eb224d..43d26e46cd 100644 --- a/test/tap/cli-test/cli-test.python.spec.ts +++ b/test/tap/cli-test/cli-test.python.spec.ts @@ -6,7 +6,11 @@ import { loadJson } from '../../utils'; export const PythonTests: AcceptanceTests = { language: 'Python', tests: { - '`test pip-app --file=requirements.txt`': (params, utils) => async (t) => { + '`test pip-app --file=requirements.txt`': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -48,12 +52,17 @@ export const PythonTests: AcceptanceTests = { path: 'pip-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls python plugin', ); }, - '`test pipenv-app --file=Pipfile`': (params, utils) => async (t) => { + '`test pipenv-app --file=Pipfile`': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -100,6 +109,7 @@ export const PythonTests: AcceptanceTests = { path: 'pipenv-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls python plugin', ); @@ -108,6 +118,7 @@ export const PythonTests: AcceptanceTests = { '`test pip-app-transitive-vuln --file=requirements.txt (actionableCliRemediation=false)`': ( params, utils, + snykHttpClient, ) => async (t) => { utils.chdirWorkspaces(); const plugin = { @@ -160,6 +171,7 @@ export const PythonTests: AcceptanceTests = { path: 'pip-app-transitive-vuln', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls python plugin', ); @@ -168,6 +180,7 @@ export const PythonTests: AcceptanceTests = { '`test pip-app-transitive-vuln --file=requirements.txt (actionableCliRemediation=true)`': ( params, utils, + snykHttpClient, ) => async (t) => { utils.chdirWorkspaces(); const plugin = { @@ -223,11 +236,16 @@ export const PythonTests: AcceptanceTests = { path: 'pip-app-transitive-vuln', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls python plugin', ); }, - '`test setup_py-app --file=setup.py`': (params, utils) => async (t) => { + '`test setup_py-app --file=setup.py`': ( + params, + utils, + snykHttpClient, + ) => async (t) => { utils.chdirWorkspaces(); const plugin = { async inspect() { @@ -275,6 +293,7 @@ export const PythonTests: AcceptanceTests = { path: 'setup_py-app', showVulnPaths: 'some', }, + snykHttpClient, ], 'calls python plugin', ); From a3591864f024a5ac04cdd8b6f4151ea146564eb1 Mon Sep 17 00:00:00 2001 From: maxjeffos <44034094+maxjeffos@users.noreply.github.com> Date: Wed, 21 Sep 2022 14:51:32 -0400 Subject: [PATCH 46/55] chore: redact static strings from analytics --- cliv2/internal/analytics/analytics.go | 34 +++++++++++ cliv2/internal/analytics/analytics_test.go | 71 ++++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/cliv2/internal/analytics/analytics.go b/cliv2/internal/analytics/analytics.go index 4f649e1e1e..d363dd0624 100644 --- a/cliv2/internal/analytics/analytics.go +++ b/cliv2/internal/analytics/analytics.go @@ -9,8 +9,10 @@ import ( "net/http" "net/url" "os" + "os/user" "regexp" "runtime" + "strings" "time" "github.com/hashicorp/go-uuid" @@ -196,6 +198,15 @@ func (a *Analytics) GetRequest() (*http.Request, error) { return nil, err } + user, err := user.Current() + if err != nil { + return nil, err + } + outputJson, err = SanitizeUsername(user.Username, sanitize_replacement_string, outputJson) + if err != nil { + return nil, err + } + analyticsUrl, _ := url.Parse(a.apiUrl + api_endpoint) if len(a.org) > 0 { query := url.Values{} @@ -247,3 +258,26 @@ func SanitizeValuesByKey(keysToFilter []string, replacementValue string, content } return content, nil } + +func SanitizeUsername(rawUserName string, replacementValue string, content []byte) ([]byte, error) { + contentStr := string(content) + contentStr = strings.ReplaceAll(contentStr, rawUserName, replacementValue) + + if strings.Contains(rawUserName, "\\") { + segments := strings.Split(rawUserName, "\\") + segmentsLen := len(segments) + if segmentsLen < 2 { + // this should never happen because we already checked for the existence of a backslash + return nil, fmt.Errorf("could not sanitize username") + } else if segmentsLen == 2 { + simpleUsername := segments[1] + contentStr = strings.ReplaceAll(contentStr, simpleUsername, replacementValue) + } else { + // don't recognize this format + fmt.Println(segments) + return nil, fmt.Errorf("could not sanitize username - unrecognized format") + } + } + + return []byte(contentStr), nil +} diff --git a/cliv2/internal/analytics/analytics_test.go b/cliv2/internal/analytics/analytics_test.go index a746cf3c83..705d6bef66 100644 --- a/cliv2/internal/analytics/analytics_test.go +++ b/cliv2/internal/analytics/analytics_test.go @@ -113,3 +113,74 @@ func Test_SanitizeValuesByKey(t *testing.T) { assert.Equal(t, expectedNumberOfRedacted, secretsCountBefore) assert.Equal(t, 0, secretsCountAfter) } + +func Test_SanitizeUsername(t *testing.T) { + type sanTest struct { + ErrorLog string + Other string + } + + rawUserName := "someuser" + simpleUsername := "someuser" + replacement := "REDACTED" + + inputStruct := sanTest{ + ErrorLog: "/Users/" + rawUserName + "/some/path", + Other: fmt.Sprintf("some other value where %s is contained", rawUserName), + } + + input, _ := json.Marshal(inputStruct) + fmt.Println("Before: " + string(input)) + + // invoke method under test + output, err := SanitizeUsername(rawUserName, replacement, input) + + fmt.Println("After: " + string(output)) + assert.Nil(t, err, "Failed to santize static values!") + + numRedacted := strings.Count(string(output), replacement) + assert.Equal(t, 2, numRedacted) + + numUsernameInstances := strings.Count(string(output), rawUserName) + assert.Equal(t, 0, numUsernameInstances) + + numSimpleUsernameInstances := strings.Count(string(output), simpleUsername) + assert.Equal(t, 0, numSimpleUsernameInstances) + + var outputStruct sanTest + json.Unmarshal(output, &outputStruct) + assert.Equal(t, "/Users/REDACTED/some/path", outputStruct.ErrorLog) + assert.Equal(t, "some other value where REDACTED is contained", outputStruct.Other) + + // Check with Windows style domain\username + rawUserName = "somedomain\\someuser" + simpleUsername = "someuser" + replacement = "REDACTED" + + inputStruct = sanTest{ + ErrorLog: fmt.Sprintf("C:\\Users\\%s\\some\\path", simpleUsername), + Other: fmt.Sprintf("some other value where %s is contained", rawUserName), + } + + input, _ = json.Marshal(inputStruct) + fmt.Println("Before: " + string(input)) + + // invoke method under test + output, err = SanitizeUsername(rawUserName, replacement, input) + + fmt.Println("After: " + string(output)) + assert.Nil(t, err, "Failed to santize static values!") + + numRedacted = strings.Count(string(output), replacement) + assert.Equal(t, 2, numRedacted) + + numUsernameInstances = strings.Count(string(output), rawUserName) + assert.Equal(t, 0, numUsernameInstances) + + numSimpleUsernameInstances = strings.Count(string(output), simpleUsername) + assert.Equal(t, 0, numSimpleUsernameInstances) + + json.Unmarshal(output, &outputStruct) + assert.Equal(t, "C:\\Users\\REDACTED\\some\\path", outputStruct.ErrorLog) + assert.Equal(t, "some other value where somedomain\\REDACTED is contained", outputStruct.Other) +} From bd063e32c5600febe5c119ad9d77a4e74f3c2e25 Mon Sep 17 00:00:00 2001 From: Ilianna Papastefanou Date: Mon, 26 Sep 2022 17:40:43 +0100 Subject: [PATCH 47/55] feat: new version to update url docs link --- .../v2/local-cache/policy-engine/constants/utils.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts index c73eefebd4..b9ddbe0d7a 100644 --- a/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts +++ b/src/lib/iac/test/v2/local-cache/policy-engine/constants/utils.ts @@ -1,12 +1,12 @@ import * as os from 'os'; const policyEngineChecksums = ` -287c2b8c97b2b6208264e5bf9dab3132c34355efdecf29974a84bd56e7e1654d snyk-iac-test_0.31.3_Darwin_x86_64 -4cb497eac74ed543dde6935e5cc0519cffbcced6bfe9a98c697b125edfb75a2e snyk-iac-test_0.31.3_Linux_arm64 -6059e32181c32f364757cb39204beea73c1ed4c477d5ae8fa8e970d5c792bb37 snyk-iac-test_0.31.3_Darwin_arm64 -7767548480f2479205bdf3d792a66d43313717a471e1c300841504b63ae2581b snyk-iac-test_0.31.3_Windows_arm64.exe -8363ae002cf64f4bb0c65ddc2312d4c6b23098032983d61d8c4c439b705750ed snyk-iac-test_0.31.3_Windows_x86_64.exe -e36cc18b60f7b41fccf5a097f685f437813b9183aa9c6fa97ea4c1fe36ac0e42 snyk-iac-test_0.31.3_Linux_x86_64 +0cb968b3547cc074c68fda705773ed87748869562fedcd580c6ec6a08c542404 snyk-iac-test_0.32.0_Linux_x86_64 +3326e5f31086dbf013361c6dc9360852953917236d211ceacde004ab0377e423 snyk-iac-test_0.32.0_Linux_arm64 +54ced701a5d739a58b3b557336895f109d6bea5b375138e12955f5c5b89a9b9e snyk-iac-test_0.32.0_Windows_x86_64.exe +5c3bdfcfcce4548a32566f60d5619b4a0045368eb273ba52956815d7eeeb737b snyk-iac-test_0.32.0_Windows_arm64.exe +6bed31a6829b4a54ba33b0f2a60fab25176720fbb99ea0eab820217faf053cb8 snyk-iac-test_0.32.0_Darwin_x86_64 +88090f61231e1327e66a60be9252cf1295b6fdb0d4817809760d9aadc3942580 snyk-iac-test_0.32.0_Darwin_arm64 `; export const policyEngineVersion = getPolicyEngineVersion(); From e8794dece21f20cc6c809f507e342030c5d0d2d4 Mon Sep 17 00:00:00 2001 From: Ofek Atar Date: Thu, 22 Sep 2022 13:55:44 +0300 Subject: [PATCH 48/55] chore: Compute analytics for experimental IaC test --- src/lib/iac/test/v2/analytics/iac-type.ts | 123 ++++++++++++++++++ src/lib/iac/test/v2/analytics/index.ts | 46 +++++++ src/lib/iac/test/v2/index.ts | 7 +- src/lib/iac/test/v2/scan/results.ts | 6 +- .../v2/analytics/fixtures/iac-analytics.json | 21 +++ .../lib/iac/test/v2/analytics/index.spec.ts | 58 +++++++++ 6 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 src/lib/iac/test/v2/analytics/iac-type.ts create mode 100644 src/lib/iac/test/v2/analytics/index.ts create mode 100644 test/jest/unit/lib/iac/test/v2/analytics/fixtures/iac-analytics.json create mode 100644 test/jest/unit/lib/iac/test/v2/analytics/index.spec.ts diff --git a/src/lib/iac/test/v2/analytics/iac-type.ts b/src/lib/iac/test/v2/analytics/iac-type.ts new file mode 100644 index 0000000000..3d0b94411e --- /dev/null +++ b/src/lib/iac/test/v2/analytics/iac-type.ts @@ -0,0 +1,123 @@ +import { SEVERITY } from '../../../../snyk-test/legacy'; +import { ResourceKind, TestOutput } from '../scan/results'; + +export function getIacType(testOutput: TestOutput): IacType { + const resourcesCountByPackageManager = getResourcesCountByPackageManager( + testOutput, + ); + + const filesCountByPackageManager = getFilesCountByPackageManager(testOutput); + + const vulnAnalyticsByPackageManager = getVulnerabilityAnalyticsByPackageManager( + testOutput, + ); + + return Object.keys(resourcesCountByPackageManager).reduce( + (acc, packageManager) => { + acc[packageManager] = { + count: filesCountByPackageManager[packageManager], + 'resource-count': resourcesCountByPackageManager[packageManager], + ...vulnAnalyticsByPackageManager[packageManager], + }; + return acc; + }, + {}, + ); +} + +export type PackageManager = ResourceKind; + +export type IacType = { + [packageManager in PackageManager]?: { + count: number; + 'resource-count': number; + } & { + [severity in SEVERITY]?: number; + }; +}; + +function getResourcesCountByPackageManager( + testOutput: TestOutput, +): ResourcesCountByPackageManager { + if (!testOutput.results?.resources?.length) { + return {}; + } + + return testOutput.results.resources.reduce((acc, resource) => { + const packageManager = resource.kind; + + if (!acc[packageManager]) { + acc[packageManager] = 0; + } + + acc[packageManager]++; + + return acc; + }, {}); +} + +export type ResourcesCountByPackageManager = { + [packageManager in PackageManager]?: number; +}; + +function getFilesCountByPackageManager( + testOutput: TestOutput, +): FilesCountByPackageManager { + if (!testOutput.results?.resources?.length) { + return {}; + } + + return Object.entries( + testOutput.results.resources.reduce((acc, resource) => { + const packageManager = resource.kind; + + if (!acc[packageManager]) { + acc[packageManager] = new Set(); + } + + acc[packageManager].add(resource.file); + + return acc; + }, {} as { [packageManager in PackageManager]: Set }), + ).reduce((acc, [packageManager, filesSet]) => { + acc[packageManager] = filesSet.size; + + return acc; + }, {}); +} + +export type FilesCountByPackageManager = { + [packageManager in PackageManager]?: number; +}; + +function getVulnerabilityAnalyticsByPackageManager( + testOutput: TestOutput, +): VulnerabilityAnalyticsByPackageManager { + if (!testOutput.results?.vulnerabilities?.length) { + return {}; + } + + return testOutput.results.vulnerabilities.reduce((acc, vuln) => { + const packageManager = vuln.resource.kind; + + if (!acc[packageManager]) { + acc[packageManager] = {}; + } + + if (!acc[packageManager][vuln.severity]) { + acc[packageManager][vuln.severity] = 0; + } + + acc[packageManager][vuln.severity]++; + + return acc; + }, {}); +} + +export type VulnerabilityAnalyticsByPackageManager = { + [packageManager in PackageManager]?: VulnerabilityAnalitycs; +}; + +export type VulnerabilityAnalitycs = { + [severity in SEVERITY]?: number; +}; diff --git a/src/lib/iac/test/v2/analytics/index.ts b/src/lib/iac/test/v2/analytics/index.ts new file mode 100644 index 0000000000..2528d93b31 --- /dev/null +++ b/src/lib/iac/test/v2/analytics/index.ts @@ -0,0 +1,46 @@ +import * as createDebugLogger from 'debug'; + +import { policyEngineReleaseVersion } from '../local-cache/policy-engine/constants'; +import { ResourceKind, TestOutput } from '../scan/results'; +import { getIacType, IacType } from './iac-type'; + +const debugLog = createDebugLogger('snyk-iac'); + +export interface IacAnalytics { + packageManager: ResourceKind[]; + 'iac-type': IacType; + 'iac-issues-count': number; + 'iac-ignored-issues-count': number; + 'iac-files-count': number; + 'iac-resources-count': number; + 'iac-test-binary-version': string; + 'iac-error-codes': number[]; + // 'iac-rules-bundle-version': string; // TODO: Add when we have the rules bundle version +} + +export function addIacAnalytics(testOutput: TestOutput): void { + const iacAnalytics = computeIacAnalytics(testOutput); + + debugLog(iacAnalytics); +} + +export function computeIacAnalytics(testOutput: TestOutput): IacAnalytics { + const iacType = getIacType(testOutput); + + return { + 'iac-type': iacType, + packageManager: Object.keys(iacType) as ResourceKind[], + 'iac-issues-count': testOutput.results?.vulnerabilities?.length || 0, + 'iac-ignored-issues-count': + testOutput.results?.scanAnalytics.ignoredCount || 0, + 'iac-files-count': Object.values(iacType).reduce( + (acc, packageManagerAnalytics) => acc + packageManagerAnalytics!.count, + 0, + ), + 'iac-resources-count': testOutput.results?.resources?.length || 0, + 'iac-error-codes': + [...new Set(testOutput.errors?.map((error) => error.code!))] || [], + 'iac-test-binary-version': policyEngineReleaseVersion, + // iacAnalytics['iac-rules-bundle-version'] = ''; // TODO: Add when we have the rules bundle version + }; +} diff --git a/src/lib/iac/test/v2/index.ts b/src/lib/iac/test/v2/index.ts index 0f16c68241..939c7ffd8e 100644 --- a/src/lib/iac/test/v2/index.ts +++ b/src/lib/iac/test/v2/index.ts @@ -2,6 +2,7 @@ import { TestConfig } from './types'; import { scan } from './scan'; import { TestOutput } from './scan/results'; import { initLocalCache } from './local-cache'; +import { addIacAnalytics } from './analytics'; export { TestConfig } from './types'; @@ -10,5 +11,9 @@ export async function test(testConfig: TestConfig): Promise { testConfig, ); - return scan(testConfig, policyEnginePath, rulesBundlePath); + const testOutput = scan(testConfig, policyEnginePath, rulesBundlePath); + + addIacAnalytics(testOutput); + + return testOutput; } diff --git a/src/lib/iac/test/v2/scan/results.ts b/src/lib/iac/test/v2/scan/results.ts index fee2a75225..fb4531f65b 100644 --- a/src/lib/iac/test/v2/scan/results.ts +++ b/src/lib/iac/test/v2/scan/results.ts @@ -71,11 +71,15 @@ export interface Resource { path?: any[]; formattedPath: string; file: string; - kind: IacProjectType | PolicyEngineTypes.State.InputTypeEnum; + kind: ResourceKind; line?: number; column?: number; } +export type ResourceKind = + | IacProjectType + | PolicyEngineTypes.State.InputTypeEnum; + export interface ScanError { message: string; code: number; diff --git a/test/jest/unit/lib/iac/test/v2/analytics/fixtures/iac-analytics.json b/test/jest/unit/lib/iac/test/v2/analytics/fixtures/iac-analytics.json new file mode 100644 index 0000000000..402e567570 --- /dev/null +++ b/test/jest/unit/lib/iac/test/v2/analytics/fixtures/iac-analytics.json @@ -0,0 +1,21 @@ +{ + "iac-type": { + "terraformconfig": { + "count": 2, + "resource-count": 4, + "medium": 4 + } + }, + "packageManager": [ + "terraformconfig" + ], + "iac-issues-count": 4, + "iac-ignored-issues-count": 3, + "iac-files-count": 2, + "iac-error-codes": [ + 2114 + ], + "iac-resources-count": 4, + "iac-test-binary-version": "test-policy-engine-release-version" + } + \ No newline at end of file diff --git a/test/jest/unit/lib/iac/test/v2/analytics/index.spec.ts b/test/jest/unit/lib/iac/test/v2/analytics/index.spec.ts new file mode 100644 index 0000000000..01a20ddf79 --- /dev/null +++ b/test/jest/unit/lib/iac/test/v2/analytics/index.spec.ts @@ -0,0 +1,58 @@ +import * as clonedeep from 'lodash.clonedeep'; +import * as path from 'path'; +import * as fs from 'fs'; + +import { SnykIacTestOutput } from '../../../../../../../../src/lib/iac/test/v2/scan/results'; +import { + computeIacAnalytics, + IacAnalytics, +} from '../../../../../../../../src/lib/iac/test/v2/analytics'; + +jest.mock( + '../../../../../../../../src/lib/iac/test/v2/local-cache/policy-engine/constants', + () => ({ + ...jest.requireActual( + '../../../../../../../../src/lib/iac/test/v2/local-cache/policy-engine/constants', + ), + policyEngineReleaseVersion: 'test-policy-engine-release-version', + }), +); + +describe('computeIacAnalytics', () => { + const snykIacTestOutputFixture: SnykIacTestOutput = JSON.parse( + fs.readFileSync( + path.join( + __dirname, + '..', + '..', + '..', + '..', + '..', + 'iac', + 'process-results', + 'fixtures', + 'snyk-iac-test-results.json', + ), + 'utf-8', + ), + ); + + const iacAnalyticsFixture: IacAnalytics = JSON.parse( + fs.readFileSync( + path.join(__dirname, 'fixtures', 'iac-analytics.json'), + 'utf-8', + ), + ); + + it('generates the correct analytics', async () => { + // Arrange + const testOutput = clonedeep(snykIacTestOutputFixture); + const expectedAnalytics = clonedeep(iacAnalyticsFixture); + + // Act + const result = computeIacAnalytics(testOutput); + + // Assert + expect(result).toStrictEqual(expectedAnalytics); + }); +}); From 5b324bdcf4a86bf03f0543d9dc25151e1fa5c21f Mon Sep 17 00:00:00 2001 From: Ofek Atar Date: Thu, 22 Sep 2022 15:28:54 +0300 Subject: [PATCH 49/55] chore: Added Slack notifications for IaC smoke tests --- .github/workflows/iac-smoke-tests-pulls.yml | 6 ++- .github/workflows/iac-smoke-tests.yml | 37 +++++++++++++-- package-lock.json | 43 ++++++++++++++++++ packages/iac-cli-alert/jest.config.js | 3 ++ packages/iac-cli-alert/package.json | 19 ++++++++ packages/iac-cli-alert/src/index.ts | 50 +++++++++++++++++++++ packages/iac-cli-alert/tsconfig.json | 8 ++++ 7 files changed, 161 insertions(+), 5 deletions(-) create mode 100644 packages/iac-cli-alert/jest.config.js create mode 100644 packages/iac-cli-alert/package.json create mode 100644 packages/iac-cli-alert/src/index.ts create mode 100644 packages/iac-cli-alert/tsconfig.json diff --git a/.github/workflows/iac-smoke-tests-pulls.yml b/.github/workflows/iac-smoke-tests-pulls.yml index 44db795c0c..086b528b85 100644 --- a/.github/workflows/iac-smoke-tests-pulls.yml +++ b/.github/workflows/iac-smoke-tests-pulls.yml @@ -84,9 +84,11 @@ jobs: echo "::set-output name=is_changed::$IS_CHANGED" - run_iac_smoke_tests: - name: Run IaC smoke tests + run_iac_smoke_tests_pulls: + name: Run IaC smoke tests (Pull Requests) uses: ./.github/workflows/iac-smoke-tests.yml needs: check_for_changed_iac_files if: ${{ needs.check_for_changed_iac_files.outputs.is_changed == 'true' }} secrets: inherit + with: + is_skip_alert: true diff --git a/.github/workflows/iac-smoke-tests.yml b/.github/workflows/iac-smoke-tests.yml index 5508aed1a6..3ef2710a10 100644 --- a/.github/workflows/iac-smoke-tests.yml +++ b/.github/workflows/iac-smoke-tests.yml @@ -6,9 +6,15 @@ on: release: types: [published] workflow_call: + inputs: + is_skip_alert: + type: boolean + required: true + default: false jobs: - run_iac_e2e_tests: + run_iac_smoke_tests: + name: Run IaC smoke tests runs-on: ${{ matrix.os }}-latest strategy: fail-fast: false @@ -22,9 +28,10 @@ jobs: - uses: actions/setup-node@v3 with: - node-version: 15 + node-version: 16.16.0 - name: Install jq on macOS + id: test if: ${{ matrix.os == 'macos' }} run: | brew install jq @@ -47,9 +54,10 @@ jobs: - name: Build Snyk CLI run: | - npm run build + npm run build:prod - name: Run IaC smoke tests - non-Windows + id: run_smoke_tests_non_windows if: ${{ matrix.os != 'windows' }} env: IAC_SMOKE_TESTS_SNYK_TOKEN: ${{ secrets.IAC_SMOKE_TESTS_SNYK_TOKEN }} @@ -58,6 +66,7 @@ jobs: npx jest --runInBand --testPathPattern '/test/smoke(/jest)?/iac/' - name: Run IaC smoke tests - Windows + id: run_smoke_tests_windows if: ${{ matrix.os == 'windows' }} shell: pwsh env: @@ -65,3 +74,25 @@ jobs: TEST_SNYK_COMMAND: ${{ format('node {0}\dist\cli\index.js', github.workspace) }} run: | npx jest --runInBand --testPathPattern '/test/smoke(/jest)?/iac/' + + trigger_iac_cli_alert: + name: Alert for failed IaC smoke tests + needs: [run_iac_smoke_tests] + if: ${{ failure() && !inputs.is_skip_alert && needs.run_iac_smoke_tests.result == 'failures' }} + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./packages/iac-cli-alert + + steps: + - uses: actions/checkout@v2 + + - uses: actions/setup-node@v3 + with: + node-version: '16.16.0' + cache: 'npm' + - run: npm ci + - run: npm start + env: + IAC_SMOKE_TESTS_SLACK_WEBHOOK_URL: ${{ secrets.IAC_SMOKE_TESTS_SLACK_WEBHOOK_URL }} + IAC_SMOKE_TESTS_OS: ${{ matrix.os }} diff --git a/package-lock.json b/package-lock.json index 7fda5bfa7b..6d2bc03767 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2223,6 +2223,10 @@ "lodash.values": "^4.3.0" } }, + "node_modules/@snyk/iac-cli-alert": { + "resolved": "packages/iac-cli-alert", + "link": true + }, "node_modules/@snyk/java-call-graph-builder": { "version": "1.23.6", "resolved": "https://registry.npmjs.org/@snyk/java-call-graph-builder/-/java-call-graph-builder-1.23.6.tgz", @@ -19990,6 +19994,29 @@ "node": ">=4.2.0" } }, + "packages/iac-cli-alert": { + "name": "@snyk/iac-cli-alert", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "@octokit/rest": "^18.0.5", + "@pagerduty/pdjs": "^2.2.0", + "@slack/webhook": "^5.0.3", + "typescript": "^4.0.2" + } + }, + "packages/iac-cli-alert/node_modules/typescript": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "packages/snyk-fix": { "name": "@snyk/fix", "version": "1.0.0-monorepo", @@ -21806,6 +21833,22 @@ "lodash.values": "^4.3.0" } }, + "@snyk/iac-cli-alert": { + "version": "file:packages/iac-cli-alert", + "requires": { + "@octokit/rest": "^18.0.5", + "@pagerduty/pdjs": "^2.2.0", + "@slack/webhook": "^5.0.3", + "typescript": "^4.0.2" + }, + "dependencies": { + "typescript": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==" + } + } + }, "@snyk/java-call-graph-builder": { "version": "1.23.6", "resolved": "https://registry.npmjs.org/@snyk/java-call-graph-builder/-/java-call-graph-builder-1.23.6.tgz", diff --git a/packages/iac-cli-alert/jest.config.js b/packages/iac-cli-alert/jest.config.js new file mode 100644 index 0000000000..f86debf953 --- /dev/null +++ b/packages/iac-cli-alert/jest.config.js @@ -0,0 +1,3 @@ +const { createJestConfig } = require('../../test/createJestConfig'); + +module.exports = createJestConfig({ displayName: '@snyk/cli-alert' }); diff --git a/packages/iac-cli-alert/package.json b/packages/iac-cli-alert/package.json new file mode 100644 index 0000000000..4cdca24f9a --- /dev/null +++ b/packages/iac-cli-alert/package.json @@ -0,0 +1,19 @@ +{ + "name": "@snyk/iac-cli-alert", + "version": "1.0.0", + "description": "Script for alerting on failing IaC smoke tests", + "main": "dist/index.js", + "private": true, + "scripts": { + "start": "npm run build && node dist/index.js", + "build": "tsc", + "dev": "tsc -w" + }, + "keywords": [], + "author": "snyk.io", + "license": "Apache-2.0", + "dependencies": { + "@slack/webhook": "^5.0.3", + "typescript": "^4.0.2" + } +} diff --git a/packages/iac-cli-alert/src/index.ts b/packages/iac-cli-alert/src/index.ts new file mode 100644 index 0000000000..fca92a3424 --- /dev/null +++ b/packages/iac-cli-alert/src/index.ts @@ -0,0 +1,50 @@ +import { + IncomingWebhook, + IncomingWebhookDefaultArguments, +} from '@slack/webhook'; + +if (!process.env.IAC_SMOKE_TESTS_SLACK_WEBHOOK_URL) { + console.error( + 'Missing the IAC_SMOKE_TESTS_SLACK_WEBHOOK_URL environment variable', + ); + process.exit(1); +} + +if (!process.env.IAC_SMOKE_TESTS_OS) { + console.error('Missing the IAC_SMOKE_TESTS_OS environment variable'); + process.exit(1); +} + +const IAC_SMOKE_TESTS_SLACK_WEBHOOK_URL = + process.env.IAC_SMOKE_TESTS_SLACK_WEBHOOK_URL; +const IAC_SMOKE_TESTS_OS = process.env.IAC_SMOKE_TESTS_OS; + +const slackWebhook = new IncomingWebhook(IAC_SMOKE_TESTS_SLACK_WEBHOOK_URL); + +async function sendSlackAlert() { + console.log('IaC smoke tests failed. Sending Slack alert...'); + const args: IncomingWebhookDefaultArguments = { + username: 'IaC CLI Alerts', + text: `An Infrastructure as Code Smoke Tests job failed. \n Operating system - ${IAC_SMOKE_TESTS_OS} \n`, + icon_emoji: 'snyk-iac', + }; + await slackWebhook.send(args); + console.log('Slack alert sent.'); +} + +async function run() { + try { + await sendSlackAlert(); + } catch (error) { + console.error(error); + process.exit(1); + } +} + +process.on('uncaughtException', (err) => { + console.error(err); + process.exit(1); +}); + +// Exec +run(); diff --git a/packages/iac-cli-alert/tsconfig.json b/packages/iac-cli-alert/tsconfig.json new file mode 100644 index 0000000000..cd8441e57e --- /dev/null +++ b/packages/iac-cli-alert/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.settings.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["./src/**/*"] +} From cc8edfb071103c241adf3a0f767d412822477993 Mon Sep 17 00:00:00 2001 From: Yaron Schwimmer Date: Wed, 28 Sep 2022 15:01:02 +0300 Subject: [PATCH 50/55] feat: container support for deleted files --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0fb1443486..409081ab60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,7 +66,7 @@ "semver": "^6.0.0", "snyk-config": "4.0.0", "snyk-cpp-plugin": "2.20.1", - "snyk-docker-plugin": "^5.4.3", + "snyk-docker-plugin": "^5.6.0", "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.23.0", "snyk-module": "3.1.0", @@ -16570,9 +16570,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/snyk-docker-plugin": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.3.tgz", - "integrity": "sha512-cv1wVei4psebrMAYyCXkrL5cYpVbPvraX5JlxDjpTJetV4C8NoQHjKH8ORXhShvkczR5ca68TAbbzK9RJ7azug==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.6.0.tgz", + "integrity": "sha512-SramvltZP4uaNP87GocZGUxa5M8AfyIXHcSufNTjy0cTLw5tpdGk8/+NVGCCe8lUwyzzDY2flrrBsAdVoxqp2Q==", "dependencies": { "@snyk/composer-lockfile-parser": "^1.4.1", "@snyk/dep-graph": "^2.3.0", @@ -32943,9 +32943,9 @@ } }, "snyk-docker-plugin": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.4.3.tgz", - "integrity": "sha512-cv1wVei4psebrMAYyCXkrL5cYpVbPvraX5JlxDjpTJetV4C8NoQHjKH8ORXhShvkczR5ca68TAbbzK9RJ7azug==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-5.6.0.tgz", + "integrity": "sha512-SramvltZP4uaNP87GocZGUxa5M8AfyIXHcSufNTjy0cTLw5tpdGk8/+NVGCCe8lUwyzzDY2flrrBsAdVoxqp2Q==", "requires": { "@snyk/composer-lockfile-parser": "^1.4.1", "@snyk/dep-graph": "^2.3.0", diff --git a/package.json b/package.json index 334cd16d25..abf8a32c63 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "semver": "^6.0.0", "snyk-config": "4.0.0", "snyk-cpp-plugin": "2.20.1", - "snyk-docker-plugin": "^5.4.3", + "snyk-docker-plugin": "^5.6.0", "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.23.0", "snyk-module": "3.1.0", From 239d4abdf3ab495ea09d80a2449706d113748f3a Mon Sep 17 00:00:00 2001 From: magdziarek Date: Wed, 28 Sep 2022 14:26:18 +0200 Subject: [PATCH 51/55] feat: refactor and add tests on gradle plugin --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 409081ab60..0b07402320 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,7 +68,7 @@ "snyk-cpp-plugin": "2.20.1", "snyk-docker-plugin": "^5.6.0", "snyk-go-plugin": "1.19.2", - "snyk-gradle-plugin": "3.23.0", + "snyk-gradle-plugin": "3.23.2", "snyk-module": "3.1.0", "snyk-mvn-plugin": "2.31.0", "snyk-nodejs-lockfile-parser": "1.38.0", @@ -16839,9 +16839,9 @@ } }, "node_modules/snyk-gradle-plugin": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.23.0.tgz", - "integrity": "sha512-cx4frLM6UDdAi8h7XGPBBHNzAFj6mcgYRIwR2ibnE72CgIGx0gGZ7iMhjhlqFHTDgYNliQdAXb3GHB8V/UXFNw==", + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.23.2.tgz", + "integrity": "sha512-CbNObx/jm7u7afQbMdNBPjkrfemvfePPwLIgFtfqwPL1dYT0wGwCgGFSDz665sGzWNaeLYG2Mr7A9AEM2D1OCQ==", "dependencies": { "@snyk/cli-interface": "2.11.3", "@snyk/dep-graph": "^1.28.0", @@ -33160,9 +33160,9 @@ } }, "snyk-gradle-plugin": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.23.0.tgz", - "integrity": "sha512-cx4frLM6UDdAi8h7XGPBBHNzAFj6mcgYRIwR2ibnE72CgIGx0gGZ7iMhjhlqFHTDgYNliQdAXb3GHB8V/UXFNw==", + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.23.2.tgz", + "integrity": "sha512-CbNObx/jm7u7afQbMdNBPjkrfemvfePPwLIgFtfqwPL1dYT0wGwCgGFSDz665sGzWNaeLYG2Mr7A9AEM2D1OCQ==", "requires": { "@snyk/cli-interface": "2.11.3", "@snyk/dep-graph": "^1.28.0", diff --git a/package.json b/package.json index abf8a32c63..a9a2ad5145 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "snyk-cpp-plugin": "2.20.1", "snyk-docker-plugin": "^5.6.0", "snyk-go-plugin": "1.19.2", - "snyk-gradle-plugin": "3.23.0", + "snyk-gradle-plugin": "3.23.2", "snyk-module": "3.1.0", "snyk-mvn-plugin": "2.31.0", "snyk-nodejs-lockfile-parser": "1.38.0", From 72bed38b42885496f390a8ed07b2f1a8f60c4d0e Mon Sep 17 00:00:00 2001 From: Ilianna Papastefanou Date: Mon, 26 Sep 2022 12:34:53 +0100 Subject: [PATCH 52/55] feat: Update feature gating for new IaC Integrated experience --- src/cli/commands/test/iac/v2/assert-iac-options.ts | 1 - src/cli/commands/test/iac/v2/index.ts | 5 +++++ src/cli/commands/test/index.ts | 5 +---- test/acceptance/fake-server.ts | 5 ++++- .../unit/cli/commands/test/iac/v2/index.spec.ts | 3 +++ .../README.md | 2 +- ...son-output.json => integrated-json-output.json} | 0 ...if-output.json => integrated-sarif-output.json} | 0 test/jest/unit/lib/iac/test/v2/json.spec.ts | 14 +++++++------- test/jest/unit/lib/iac/test/v2/sarif.spec.ts | 12 ++++++------ test/smoke/iac/test.spec.ts | 6 ++---- 11 files changed, 29 insertions(+), 24 deletions(-) rename test/jest/unit/iac/process-results/fixtures/{experimental-json-output.json => integrated-json-output.json} (100%) rename test/jest/unit/iac/process-results/fixtures/{experimental-sarif-output.json => integrated-sarif-output.json} (100%) diff --git a/src/cli/commands/test/iac/v2/assert-iac-options.ts b/src/cli/commands/test/iac/v2/assert-iac-options.ts index 951a4f82c7..c5aa94d230 100644 --- a/src/cli/commands/test/iac/v2/assert-iac-options.ts +++ b/src/cli/commands/test/iac/v2/assert-iac-options.ts @@ -26,7 +26,6 @@ const keys: (keyof IaCTestFlags)[] = [ 'json-file-output', 'sarif-file-output', 'scan', - 'experimental', 'var-file', 'detectionDepth', 'cloud-context', diff --git a/src/cli/commands/test/iac/v2/index.ts b/src/cli/commands/test/iac/v2/index.ts index 23a245b1f3..8bbb2b9297 100644 --- a/src/cli/commands/test/iac/v2/index.ts +++ b/src/cli/commands/test/iac/v2/index.ts @@ -14,6 +14,7 @@ import { getFlag } from '../index'; import { IaCTestFlags } from '../local-execution/types'; import { findAndLoadPolicy } from '../../../../../lib/policy'; import { assertIacV2Options } from './assert-iac-options'; +import { UnsupportedEntitlementError } from '../../../../../lib/errors/unsupported-entitlement-error'; export async function test( paths: string[], @@ -23,6 +24,10 @@ export async function test( const testConfig = await prepareTestConfig(paths, options); const { orgSettings } = testConfig; + if (!orgSettings.entitlements?.infrastructureAsCode) { + throw new UnsupportedEntitlementError('infrastructureAsCode'); + } + const testSpinner = buildSpinner(options); printHeader(options); diff --git a/src/cli/commands/test/index.ts b/src/cli/commands/test/index.ts index 3e0fa77435..cbad39fd0f 100644 --- a/src/cli/commands/test/index.ts +++ b/src/cli/commands/test/index.ts @@ -58,10 +58,7 @@ export default async function test( const options = setDefaultTestOptions(originalOptions); if (originalOptions.iac) { // temporary placeholder for the "new" flow that integrates with UPE - if ( - (await hasFeatureFlag('iacCliUnifiedEngine', options)) && - options.experimental - ) { + if (await hasFeatureFlag('iacIntegratedExperience', options)) { return await iacTestCommandV2.test(paths, originalOptions); } else { return await iacTestCommand(...args); diff --git a/test/acceptance/fake-server.ts b/test/acceptance/fake-server.ts index d7784326af..aa0573232b 100644 --- a/test/acceptance/fake-server.ts +++ b/test/acceptance/fake-server.ts @@ -7,7 +7,10 @@ import * as path from 'path'; import { getFixturePath } from '../jest/util/getFixturePath'; const featureFlagDefaults = (): Map => { - return new Map([['cliFailFast', false]]); + return new Map([ + ['cliFailFast', false], + ['iacIntegratedExperience', false], + ]); }; export type FakeServer = { diff --git a/test/jest/unit/cli/commands/test/iac/v2/index.spec.ts b/test/jest/unit/cli/commands/test/iac/v2/index.spec.ts index 77ae812e54..779f574938 100644 --- a/test/jest/unit/cli/commands/test/iac/v2/index.spec.ts +++ b/test/jest/unit/cli/commands/test/iac/v2/index.spec.ts @@ -53,6 +53,9 @@ describe('test', () => { isLicensesEnabled: false, isPrivate: false, }, + entitlements: { + infrastructureAsCode: true, + }, }; const scanFixture = JSON.parse(fs.readFileSync(scanFixturePath, 'utf-8')); diff --git a/test/jest/unit/iac/process-results/fixtures/input-files-for-snyk-iac-test-fixtures/README.md b/test/jest/unit/iac/process-results/fixtures/input-files-for-snyk-iac-test-fixtures/README.md index 0cd124e2a2..f06c6d2b43 100644 --- a/test/jest/unit/iac/process-results/fixtures/input-files-for-snyk-iac-test-fixtures/README.md +++ b/test/jest/unit/iac/process-results/fixtures/input-files-for-snyk-iac-test-fixtures/README.md @@ -7,7 +7,7 @@ console.log(JSON.stringify(scanResult, null, 2)); ``` 3. scan the directory by running the following command: ``` -snyk-dev iac test --experimental vpc_group.tf plan.json invalid_file.txt +snyk-dev iac test vpc_group.tf plan.json invalid_file.txt ``` 4. save the scan results in the [primary fixture file](../snyk-iac-test-results.json) 5. start regenerating fixtures like a mad (wo)man!!! \ No newline at end of file diff --git a/test/jest/unit/iac/process-results/fixtures/experimental-json-output.json b/test/jest/unit/iac/process-results/fixtures/integrated-json-output.json similarity index 100% rename from test/jest/unit/iac/process-results/fixtures/experimental-json-output.json rename to test/jest/unit/iac/process-results/fixtures/integrated-json-output.json diff --git a/test/jest/unit/iac/process-results/fixtures/experimental-sarif-output.json b/test/jest/unit/iac/process-results/fixtures/integrated-sarif-output.json similarity index 100% rename from test/jest/unit/iac/process-results/fixtures/experimental-sarif-output.json rename to test/jest/unit/iac/process-results/fixtures/integrated-sarif-output.json diff --git a/test/jest/unit/lib/iac/test/v2/json.spec.ts b/test/jest/unit/lib/iac/test/v2/json.spec.ts index a74233face..50289d5eff 100644 --- a/test/jest/unit/lib/iac/test/v2/json.spec.ts +++ b/test/jest/unit/lib/iac/test/v2/json.spec.ts @@ -30,7 +30,7 @@ describe('convertEngineToJsonResults', () => { return isError ? new SnykIacTestError(item) : item; }); - const experimentalJsonOutputFixtureContent = fs.readFileSync( + const integratedJsonOutputFixtureContent = fs.readFileSync( path.join( __dirname, '..', @@ -40,15 +40,15 @@ describe('convertEngineToJsonResults', () => { 'iac', 'process-results', 'fixtures', - 'experimental-json-output.json', + 'integrated-json-output.json', ), 'utf-8', ); - let experimentalJsonOutputFixture: Array = JSON.parse( - experimentalJsonOutputFixtureContent, + let integratedJsonOutputFixture: Array = JSON.parse( + integratedJsonOutputFixtureContent, ); - experimentalJsonOutputFixture = experimentalJsonOutputFixture.map((item) => + integratedJsonOutputFixture = integratedJsonOutputFixture.map((item) => !('error' in item) ? { ...item, path: process.cwd() } : item, ); @@ -75,12 +75,12 @@ describe('convertEngineToJsonResults', () => { orgSettings, }); - experimentalJsonOutputFixture.forEach((item) => { + integratedJsonOutputFixture.forEach((item) => { if ('targetFilePath' in item) { item.targetFilePath = path.resolve(item.targetFile); } }); - expect(result).toEqual(experimentalJsonOutputFixture); + expect(result).toEqual(integratedJsonOutputFixture); }); }); diff --git a/test/jest/unit/lib/iac/test/v2/sarif.spec.ts b/test/jest/unit/lib/iac/test/v2/sarif.spec.ts index ce74f5a2a8..ec201a2be0 100644 --- a/test/jest/unit/lib/iac/test/v2/sarif.spec.ts +++ b/test/jest/unit/lib/iac/test/v2/sarif.spec.ts @@ -22,7 +22,7 @@ describe('convertEngineToSarifResults', () => { ); const snykIacTestFixture: TestOutput = JSON.parse(snykIacTestFixtureContent); - const experimentalSarifOutputFixtureContent = fs.readFileSync( + const integratedSarifOutputFixtureContent = fs.readFileSync( path.join( __dirname, '..', @@ -32,21 +32,21 @@ describe('convertEngineToSarifResults', () => { 'iac', 'process-results', 'fixtures', - 'experimental-sarif-output.json', + 'integrated-sarif-output.json', ), 'utf-8', ); - const experimentalSarifOutputFixture: sarif.Log = JSON.parse( - experimentalSarifOutputFixtureContent, + const integratedSarifOutputFixture: sarif.Log = JSON.parse( + integratedSarifOutputFixtureContent, ); - experimentalSarifOutputFixture.runs[0].originalUriBaseIds!.PROJECTROOT.uri = pathToFileURL( + integratedSarifOutputFixture.runs[0].originalUriBaseIds!.PROJECTROOT.uri = pathToFileURL( process.cwd() + '/', ).href; it('returns expected SARIF result', () => { const result = convertEngineToSarifResults(snykIacTestFixture); - expect(result).toEqual(experimentalSarifOutputFixture); + expect(result).toEqual(integratedSarifOutputFixture); }); }); diff --git a/test/smoke/iac/test.spec.ts b/test/smoke/iac/test.spec.ts index 0e6253c2f6..14649cfda4 100644 --- a/test/smoke/iac/test.spec.ts +++ b/test/smoke/iac/test.spec.ts @@ -2,7 +2,7 @@ import { run } from '../../jest/acceptance/iac/helpers'; jest.setTimeout(1_000 * 90); -describe('snyk iac test --experimental', () => { +describe('snyk iac test', () => { beforeAll(async () => { await login(); }); @@ -12,9 +12,7 @@ describe('snyk iac test --experimental', () => { const filePath = 'iac/depth_detection/root.tf'; // Act - const { stderr, stdout, exitCode } = await run( - `snyk iac test --experimental ${filePath}`, - ); + const { stderr, stdout, exitCode } = await run(`snyk iac test ${filePath}`); // Assert expect(stdout).toContain('Infrastructure as Code'); From 5821ed4f514cbb0a80c05cd6bb137d2d24a48b06 Mon Sep 17 00:00:00 2001 From: gitphill Date: Thu, 15 Sep 2022 16:15:31 +0100 Subject: [PATCH 53/55] fix: unmanaged scan unknown archives See https://github.com/snyk/snyk-mvn-plugin/pull/137 Adding warning message to indicate when projects have a dep-graph that contains packages with unknown versions (like in the Snyk UI). --- package-lock.json | 14 +++++----- package.json | 2 +- src/lib/dep-graph.ts | 13 +++++++++ src/lib/formatters/test/display-result.ts | 10 +++++++ .../formatters/test/format-test-results.ts | 4 ++- src/lib/snyk-test/legacy.ts | 1 + src/lib/snyk-test/run-test.ts | 6 +++++ .../ruby-app-no-vulns/test-graph-result.json | 1 + .../ruby-app-no-vulns/test-result.json | 1 + .../test-graph-result-cloud-ignore.json | 1 + .../ruby-app-policy/test-graph-result.json | 1 + .../test-result-cloud-ignore.json | 1 + .../ruby-app-policy/test-result.json | 1 + .../test-result-critical-severity.json | 1 + .../test-result-high-severity.json | 1 + .../test-result-low-severity.json | 1 + .../test-result-medium-severity.json | 1 + .../sbt-simple-struts/legacy-res-json.json | 1 + .../sbt-simple-struts/test-graph-result.json | 1 + test/jest/acceptance/dep-graph.spec.ts | 27 +++++++++++++++++++ .../unit/python/snyk-test-pyproject.spec.ts | 4 +++ 21 files changed, 84 insertions(+), 9 deletions(-) create mode 100644 src/lib/dep-graph.ts create mode 100644 test/jest/acceptance/dep-graph.spec.ts diff --git a/package-lock.json b/package-lock.json index 0b07402320..f4c221ad70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -70,7 +70,7 @@ "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.23.2", "snyk-module": "3.1.0", - "snyk-mvn-plugin": "2.31.0", + "snyk-mvn-plugin": "2.31.1", "snyk-nodejs-lockfile-parser": "1.38.0", "snyk-nuget-plugin": "1.23.5", "snyk-php-plugin": "1.9.2", @@ -16996,9 +16996,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/snyk-mvn-plugin": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/snyk-mvn-plugin/-/snyk-mvn-plugin-2.31.0.tgz", - "integrity": "sha512-b1H8F0t5zHDygMQytebBn+oCY3Vt8XTTh/qvMxdv0xQaHHs3kq3O4R/kXCn/rCMjBhVGkObcMWwb32rNrrK89g==", + "version": "2.31.1", + "resolved": "https://registry.npmjs.org/snyk-mvn-plugin/-/snyk-mvn-plugin-2.31.1.tgz", + "integrity": "sha512-m1kVejTQBEQTC1fhdoldyeAVxN+YsvQboeJzJ+tnzuQscINiFX5467BS206gRvC6oIS6YfCXpCiMeq0sW09EDA==", "dependencies": { "@snyk/cli-interface": "2.11.3", "@snyk/dep-graph": "^1.23.1", @@ -33282,9 +33282,9 @@ } }, "snyk-mvn-plugin": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/snyk-mvn-plugin/-/snyk-mvn-plugin-2.31.0.tgz", - "integrity": "sha512-b1H8F0t5zHDygMQytebBn+oCY3Vt8XTTh/qvMxdv0xQaHHs3kq3O4R/kXCn/rCMjBhVGkObcMWwb32rNrrK89g==", + "version": "2.31.1", + "resolved": "https://registry.npmjs.org/snyk-mvn-plugin/-/snyk-mvn-plugin-2.31.1.tgz", + "integrity": "sha512-m1kVejTQBEQTC1fhdoldyeAVxN+YsvQboeJzJ+tnzuQscINiFX5467BS206gRvC6oIS6YfCXpCiMeq0sW09EDA==", "requires": { "@snyk/cli-interface": "2.11.3", "@snyk/dep-graph": "^1.23.1", diff --git a/package.json b/package.json index a9a2ad5145..07d2f2618f 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "snyk-go-plugin": "1.19.2", "snyk-gradle-plugin": "3.23.2", "snyk-module": "3.1.0", - "snyk-mvn-plugin": "2.31.0", + "snyk-mvn-plugin": "2.31.1", "snyk-nodejs-lockfile-parser": "1.38.0", "snyk-nuget-plugin": "1.23.5", "snyk-php-plugin": "1.9.2", diff --git a/src/lib/dep-graph.ts b/src/lib/dep-graph.ts new file mode 100644 index 0000000000..fa688abb14 --- /dev/null +++ b/src/lib/dep-graph.ts @@ -0,0 +1,13 @@ +import { DepGraph } from '@snyk/dep-graph'; + +export function hasUnknownVersions(depGraph?: DepGraph): boolean { + if (!depGraph) { + return false; + } + for (const pkg of depGraph.getPkgs()) { + if (pkg.version === 'unknown') { + return true; + } + } + return false; +} diff --git a/src/lib/formatters/test/display-result.ts b/src/lib/formatters/test/display-result.ts index 952b528d9e..6e47cbb395 100644 --- a/src/lib/formatters/test/display-result.ts +++ b/src/lib/formatters/test/display-result.ts @@ -22,6 +22,7 @@ import { getDisplayedOutput, } from '../../../lib/formatters/test/format-test-results'; import { showMultiScanTip } from '../show-multi-scan-tip'; +import * as theme from '../../theme'; export function displayResult( res: TestResult, @@ -66,6 +67,13 @@ export function displayResult( ); const multiProjAdvice = multiProjectTip ? `\n\n${multiProjectTip}` : ''; + const warningMessage = theme.color.status.warn( + `${theme.icon.WARNING} Warning!`, + ); + const hasUnknownVersions = res.hasUnknownVersions + ? `\n\n${warningMessage} Some dependencies in this project could not be identified.` + : ''; + // OK => no vulns found, return if (res.ok && res.vulnerabilities.length === 0) { const vulnPathsText = options.showVulnPaths @@ -98,6 +106,7 @@ export function displayResult( meta + '\n\n' + summaryOKText + + hasUnknownVersions + multiProjAdvice + (isCI() ? '' @@ -115,6 +124,7 @@ export function displayResult( projectType, meta, prefix, + hasUnknownVersions, multiProjAdvice, dockerAdvice, ); diff --git a/src/lib/formatters/test/format-test-results.ts b/src/lib/formatters/test/format-test-results.ts index 7affceb83c..d450c15c65 100644 --- a/src/lib/formatters/test/format-test-results.ts +++ b/src/lib/formatters/test/format-test-results.ts @@ -142,6 +142,7 @@ export function getDisplayedOutput( projectType: SupportedProjectTypes, meta: string, prefix: string, + hasUnknownVersions: string, multiProjAdvice: string, dockerAdvice: string, ): string { @@ -168,7 +169,8 @@ export function getDisplayedOutput( vulnCountText += '.'; } - const summary = testedInfoText + ', ' + chalk.red.bold(vulnCountText); + const summary = + testedInfoText + ', ' + chalk.red.bold(vulnCountText) + hasUnknownVersions; const fixTip = showFixTip(projectType, res, options); const fixAdvice = fixTip ? `\n\n${fixTip}` : ''; diff --git a/src/lib/snyk-test/legacy.ts b/src/lib/snyk-test/legacy.ts index 43450643e3..fec920e9fc 100644 --- a/src/lib/snyk-test/legacy.ts +++ b/src/lib/snyk-test/legacy.ts @@ -177,6 +177,7 @@ export interface TestResult extends LegacyVulnApiResult { displayTargetFile?: string; // used for display only foundProjectCount?: number; scanResult?: ScanResult; + hasUnknownVersions?: boolean; } interface UpgradePathItem { diff --git a/src/lib/snyk-test/run-test.ts b/src/lib/snyk-test/run-test.ts index 5f8d8e4632..6c1ebd8c32 100644 --- a/src/lib/snyk-test/run-test.ts +++ b/src/lib/snyk-test/run-test.ts @@ -66,6 +66,7 @@ import { Issue } from '../ecosystems/types'; import { assembleEcosystemPayloads } from './assemble-payloads'; import { makeRequest } from '../request'; import { spinner } from '../spinner'; +import { hasUnknownVersions } from '../dep-graph'; const debug = debugModule('snyk:run-test'); @@ -121,6 +122,7 @@ function prepareEcosystemResponseForParsing( payloadPolicy: payloadBody?.policy, platform, scanResult: payloadBody, + hasUnknownVersions: hasUnknownVersions(depGraph), }; } @@ -156,6 +158,7 @@ function prepareLanguagesResponseForParsing(payload: Payload) { foundProjectCount, displayTargetFile, dockerfilePackages, + hasUnknownVersions: hasUnknownVersions(depGraph), }; } @@ -234,6 +237,7 @@ async function sendAndParseResults( dockerfilePackages, platform, scanResult, + hasUnknownVersions, } = prepareResponseForParsing( payloadCopy, res as TestDependenciesResponse, @@ -267,6 +271,7 @@ async function sendAndParseResults( displayTargetFile, platform, scanResult, + hasUnknownVersions, }); } return results; @@ -601,6 +606,7 @@ async function assembleLocalPayloads( maybePrintDepTree(options, pkg as DepTree); } } + const project = scannedProject as ScannedProjectCustom; const packageManager = extractPackageManager(project, deps, options); diff --git a/test/acceptance/workspaces/ruby-app-no-vulns/test-graph-result.json b/test/acceptance/workspaces/ruby-app-no-vulns/test-graph-result.json index bec90fad65..ea2246ab53 100644 --- a/test/acceptance/workspaces/ruby-app-no-vulns/test-graph-result.json +++ b/test/acceptance/workspaces/ruby-app-no-vulns/test-graph-result.json @@ -8,6 +8,7 @@ "isLicensesEnabled": false, "licensesPolicy": null, "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.13.1\nignore: {}\npatch: {}\n", + "hasUnknownVersions": false, "ignoreSettings": null, "org": "test-org" }, diff --git a/test/acceptance/workspaces/ruby-app-no-vulns/test-result.json b/test/acceptance/workspaces/ruby-app-no-vulns/test-result.json index dbc3b9de19..ce2c3a2959 100644 --- a/test/acceptance/workspaces/ruby-app-no-vulns/test-result.json +++ b/test/acceptance/workspaces/ruby-app-no-vulns/test-result.json @@ -7,6 +7,7 @@ "isPrivate": true, "packageManager": "rubygems", "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.13.1\nignore: {}\npatch: {}\n", + "hasUnknownVersions": false, "ignoreSettings": null, "projectName": "ruby-app-no-vulns", "displayTargetFile": "Gemfile", diff --git a/test/acceptance/workspaces/ruby-app-policy/test-graph-result-cloud-ignore.json b/test/acceptance/workspaces/ruby-app-policy/test-graph-result-cloud-ignore.json index 72451e5d97..ab70cd31fb 100644 --- a/test/acceptance/workspaces/ruby-app-policy/test-graph-result-cloud-ignore.json +++ b/test/acceptance/workspaces/ruby-app-policy/test-graph-result-cloud-ignore.json @@ -386,6 +386,7 @@ "isLicensesEnabled": false, "licensesPolicy": null, "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.13.1\n# ignores vulnerabilities until expiry date; change duration by modifying expiry date\nignore:\n SNYK-RUBY-LYNX-20160:\n - '*':\n reason: will check again in 2100\n expires: 2100-01-01T00:00:00.000Z\n source: cli\n SNYK-RUBY-SANITIZE-22024:\n - '*':\n reason: who needs sanitization anyway\n created: '2018-11-23T07:33:16.687Z'\n ignoredBy:\n id: 3c2d7dd6-e86e-4842-8124-5766bf55e060\n name: brian@doogdog.com\n email: brian@doogdog.com\n reasonType: temporary-ignore\n disregardIfFixable: false\n source: api\npatch: {}\n", + "hasUnknownVersions": false, "ignoreSettings": null, "org": "test-org" }, diff --git a/test/acceptance/workspaces/ruby-app-policy/test-graph-result.json b/test/acceptance/workspaces/ruby-app-policy/test-graph-result.json index 36e16d5c92..7aed8b0b9d 100644 --- a/test/acceptance/workspaces/ruby-app-policy/test-graph-result.json +++ b/test/acceptance/workspaces/ruby-app-policy/test-graph-result.json @@ -386,6 +386,7 @@ "isLicensesEnabled": false, "licensesPolicy": null, "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.13.1\n# ignores vulnerabilities until expiry date; change duration by modifying expiry date\nignore:\n SNYK-RUBY-LYNX-20160:\n - '*':\n reason: will check again in 2100\n expires: 2100-01-01T00:00:00.000Z\n source: cli\npatch: {}\n", + "hasUnknownVersions": false, "ignoreSettings": null, "org": "test-org" }, diff --git a/test/acceptance/workspaces/ruby-app-policy/test-result-cloud-ignore.json b/test/acceptance/workspaces/ruby-app-policy/test-result-cloud-ignore.json index d7a080a423..84133948ce 100644 --- a/test/acceptance/workspaces/ruby-app-policy/test-result-cloud-ignore.json +++ b/test/acceptance/workspaces/ruby-app-policy/test-result-cloud-ignore.json @@ -281,6 +281,7 @@ "isPrivate": true, "packageManager": "rubygems", "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.13.1\n# ignores vulnerabilities until expiry date; change duration by modifying expiry date\nignore:\n SNYK-RUBY-LYNX-20160:\n - '*':\n reason: will check again in 2100\n expires: 2100-01-01T00:00:00.000Z\n source: cli\n SNYK-RUBY-SANITIZE-22024:\n - '*':\n reason: who needs sanitization anyway\n created: '2018-11-23T07:33:16.687Z'\n ignoredBy:\n id: 3c2d7dd6-e86e-4842-8124-5766bf55e060\n name: brian@doogdog.com\n email: brian@doogdog.com\n reasonType: temporary-ignore\n disregardIfFixable: false\n source: api\npatch: {}\n", + "hasUnknownVersions": false, "ignoreSettings": null, "summary": "7 vulnerable dependency paths", "displayTargetFile": "Gemfile", diff --git a/test/acceptance/workspaces/ruby-app-policy/test-result.json b/test/acceptance/workspaces/ruby-app-policy/test-result.json index c07cf27285..581d9739c9 100644 --- a/test/acceptance/workspaces/ruby-app-policy/test-result.json +++ b/test/acceptance/workspaces/ruby-app-policy/test-result.json @@ -335,6 +335,7 @@ "isPrivate": true, "packageManager": "rubygems", "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.13.1\n# ignores vulnerabilities until expiry date; change duration by modifying expiry date\nignore:\n SNYK-RUBY-LYNX-20160:\n - '*':\n reason: will check again in 2100\n expires: 2100-01-01T00:00:00.000Z\n source: cli\npatch: {}\n", + "hasUnknownVersions": false, "ignoreSettings": null, "summary": "7 vulnerable dependency paths", "displayTargetFile": "Gemfile", diff --git a/test/acceptance/workspaces/ruby-app-thresholds/test-result-critical-severity.json b/test/acceptance/workspaces/ruby-app-thresholds/test-result-critical-severity.json index b6e0915c88..2142a4a43c 100644 --- a/test/acceptance/workspaces/ruby-app-thresholds/test-result-critical-severity.json +++ b/test/acceptance/workspaces/ruby-app-thresholds/test-result-critical-severity.json @@ -126,6 +126,7 @@ "ignore": [], "patch": [] }, + "hasUnknownVersions": false, "projectName": "ruby-app-thresholds", "uniqueCount": 1, "path": "ruby-app-thresholds" diff --git a/test/acceptance/workspaces/ruby-app-thresholds/test-result-high-severity.json b/test/acceptance/workspaces/ruby-app-thresholds/test-result-high-severity.json index 73b8043bbb..1570fed8c2 100644 --- a/test/acceptance/workspaces/ruby-app-thresholds/test-result-high-severity.json +++ b/test/acceptance/workspaces/ruby-app-thresholds/test-result-high-severity.json @@ -236,6 +236,7 @@ "ignore": [], "patch": [] }, + "hasUnknownVersions": false, "projectName": "ruby-app-thresholds", "uniqueCount": 3, "path": "ruby-app-thresholds" diff --git a/test/acceptance/workspaces/ruby-app-thresholds/test-result-low-severity.json b/test/acceptance/workspaces/ruby-app-thresholds/test-result-low-severity.json index d5a7656a1e..82e9a12a4c 100644 --- a/test/acceptance/workspaces/ruby-app-thresholds/test-result-low-severity.json +++ b/test/acceptance/workspaces/ruby-app-thresholds/test-result-low-severity.json @@ -395,6 +395,7 @@ "ignore": [], "patch": [] }, + "hasUnknownVersions": false, "projectName": "ruby-app-thresholds", "uniqueCount": 6, "path": "ruby-app-thresholds" diff --git a/test/acceptance/workspaces/ruby-app-thresholds/test-result-medium-severity.json b/test/acceptance/workspaces/ruby-app-thresholds/test-result-medium-severity.json index ebfeef4395..b596d51628 100644 --- a/test/acceptance/workspaces/ruby-app-thresholds/test-result-medium-severity.json +++ b/test/acceptance/workspaces/ruby-app-thresholds/test-result-medium-severity.json @@ -344,6 +344,7 @@ "ignore": [], "patch": [] }, + "hasUnknownVersions": false, "projectName": "ruby-app-thresholds", "uniqueCount": 5, "path": "ruby-app-thresholds" diff --git a/test/acceptance/workspaces/sbt-simple-struts/legacy-res-json.json b/test/acceptance/workspaces/sbt-simple-struts/legacy-res-json.json index 9fd68ca72b..e22d06e4da 100644 --- a/test/acceptance/workspaces/sbt-simple-struts/legacy-res-json.json +++ b/test/acceptance/workspaces/sbt-simple-struts/legacy-res-json.json @@ -1961,6 +1961,7 @@ "isPrivate": true, "packageManager": "maven", "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.13.1\nignore: {}\npatch: {}\n", + "hasUnknownVersions": false, "ignoreSettings": null, "summary": "31 vulnerable dependency paths", "displayTargetFile": "build.sbt", diff --git a/test/acceptance/workspaces/sbt-simple-struts/test-graph-result.json b/test/acceptance/workspaces/sbt-simple-struts/test-graph-result.json index 0f0525b275..abf6bda6e6 100644 --- a/test/acceptance/workspaces/sbt-simple-struts/test-graph-result.json +++ b/test/acceptance/workspaces/sbt-simple-struts/test-graph-result.json @@ -2259,6 +2259,7 @@ } }, "policy": "# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.\nversion: v1.13.1\nignore: {}\npatch: {}\n", + "hasUnknownVersions": false, "ignoreSettings": null, "org": "snyk" }, diff --git a/test/jest/acceptance/dep-graph.spec.ts b/test/jest/acceptance/dep-graph.spec.ts new file mode 100644 index 0000000000..53f33dd729 --- /dev/null +++ b/test/jest/acceptance/dep-graph.spec.ts @@ -0,0 +1,27 @@ +import { DepGraphBuilder } from '@snyk/dep-graph'; +import { hasUnknownVersions } from '../../../src/lib/dep-graph'; + +describe('dep-graph', () => { + describe('hasUnknownVersions', () => { + it('returns true when dep-graph has unknown versions', () => { + const builder = new DepGraphBuilder({ name: 'maven' }); + builder.addPkgNode({ name: 'test', version: 'unknown' }, 'test@unknown'); + builder.connectDep(builder.rootNodeId, 'test@unknown'); + const depGraph = builder.build(); + const received = hasUnknownVersions(depGraph); + expect(received).toBe(true); + }); + it('returns false when dep-graph does not have unknown versions', () => { + const builder = new DepGraphBuilder({ name: 'maven' }); + builder.addPkgNode({ name: 'test', version: '1.2.3' }, 'test@1.2.3'); + builder.connectDep(builder.rootNodeId, 'test@1.2.3'); + const depGraph = builder.build(); + const received = hasUnknownVersions(depGraph); + expect(received).toBe(false); + }); + it('returns false when dep-graph is undefined', () => { + const received = hasUnknownVersions(undefined); + expect(received).toBe(false); + }); + }); +}); diff --git a/test/jest/unit/python/snyk-test-pyproject.spec.ts b/test/jest/unit/python/snyk-test-pyproject.spec.ts index 482e4fbf63..769caefbe5 100644 --- a/test/jest/unit/python/snyk-test-pyproject.spec.ts +++ b/test/jest/unit/python/snyk-test-pyproject.spec.ts @@ -103,6 +103,7 @@ describe('snyk test for python project', () => { foundProjectCount: undefined, displayTargetFile: 'pyproject.toml', platform: undefined, + hasUnknownVersions: false, path: fixturePath, }; expect(result).toMatchObject({ @@ -183,6 +184,7 @@ describe('snyk test for python project', () => { foundProjectCount: undefined, displayTargetFile: 'Pipfile', platform: undefined, + hasUnknownVersions: false, path: fixturePath, }; expect(result).toMatchObject({ @@ -283,6 +285,7 @@ describe('snyk test for python project', () => { projectName: undefined, displayTargetFile: 'Pipfile', platform: undefined, + hasUnknownVersions: false, path: fixturePath, }; const expectedPyprojectResultObject = { @@ -307,6 +310,7 @@ describe('snyk test for python project', () => { projectName: undefined, displayTargetFile: 'pyproject.toml', platform: undefined, + hasUnknownVersions: false, path: fixturePath, }; expect(result).toMatchObject({ From acf4c5c3129153a9e86800bc19c61892e746c047 Mon Sep 17 00:00:00 2001 From: Ofek Atar Date: Thu, 29 Sep 2022 12:59:06 +0300 Subject: [PATCH 54/55] chore: Send integrated IaC test analytics --- src/lib/iac/test/v2/analytics/index.ts | 49 ++++++++++--------- .../lib/iac/test/v2/analytics/index.spec.ts | 18 +++++-- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/lib/iac/test/v2/analytics/index.ts b/src/lib/iac/test/v2/analytics/index.ts index 2528d93b31..95d11d6634 100644 --- a/src/lib/iac/test/v2/analytics/index.ts +++ b/src/lib/iac/test/v2/analytics/index.ts @@ -1,46 +1,49 @@ -import * as createDebugLogger from 'debug'; - import { policyEngineReleaseVersion } from '../local-cache/policy-engine/constants'; import { ResourceKind, TestOutput } from '../scan/results'; +import * as analytics from '../../../../../lib/analytics'; import { getIacType, IacType } from './iac-type'; -const debugLog = createDebugLogger('snyk-iac'); - export interface IacAnalytics { + iacType: IacType; packageManager: ResourceKind[]; - 'iac-type': IacType; - 'iac-issues-count': number; - 'iac-ignored-issues-count': number; - 'iac-files-count': number; - 'iac-resources-count': number; - 'iac-test-binary-version': string; - 'iac-error-codes': number[]; - // 'iac-rules-bundle-version': string; // TODO: Add when we have the rules bundle version + iacIssuesCount: number; + iacIgnoredIssuesCount: number; + iacFilesCount: number; + iacResourcesCount: number; + iacErrorCodes: number[]; + iacTestBinaryVersion: string; + // iacRulesBundleVersion: string; // TODO: Add when we have the rules bundle version } export function addIacAnalytics(testOutput: TestOutput): void { const iacAnalytics = computeIacAnalytics(testOutput); - debugLog(iacAnalytics); + analytics.add('iac-type', iacAnalytics.iacType); + analytics.add('packageManager', iacAnalytics.packageManager); + analytics.add('iac-issues-count', iacAnalytics.iacIssuesCount); + analytics.add('iac-ignored-issues-count', iacAnalytics.iacIgnoredIssuesCount); + analytics.add('iac-files-count', iacAnalytics.iacFilesCount); + analytics.add('iac-resources-count', iacAnalytics.iacResourcesCount); + analytics.add('iac-error-codes', iacAnalytics.iacErrorCodes); + analytics.add('iac-test-binary-version', iacAnalytics.iacTestBinaryVersion); } -export function computeIacAnalytics(testOutput: TestOutput): IacAnalytics { +function computeIacAnalytics(testOutput: TestOutput): IacAnalytics { const iacType = getIacType(testOutput); return { - 'iac-type': iacType, + iacType, packageManager: Object.keys(iacType) as ResourceKind[], - 'iac-issues-count': testOutput.results?.vulnerabilities?.length || 0, - 'iac-ignored-issues-count': - testOutput.results?.scanAnalytics.ignoredCount || 0, - 'iac-files-count': Object.values(iacType).reduce( + iacIssuesCount: testOutput.results?.vulnerabilities?.length || 0, + iacIgnoredIssuesCount: testOutput.results?.scanAnalytics.ignoredCount || 0, + iacFilesCount: Object.values(iacType).reduce( (acc, packageManagerAnalytics) => acc + packageManagerAnalytics!.count, 0, ), - 'iac-resources-count': testOutput.results?.resources?.length || 0, - 'iac-error-codes': + iacResourcesCount: testOutput.results?.resources?.length || 0, + iacErrorCodes: [...new Set(testOutput.errors?.map((error) => error.code!))] || [], - 'iac-test-binary-version': policyEngineReleaseVersion, - // iacAnalytics['iac-rules-bundle-version'] = ''; // TODO: Add when we have the rules bundle version + iacTestBinaryVersion: policyEngineReleaseVersion, + // iacRulesBundleVersion = ''; // TODO: Add when we have the rules bundle version }; } diff --git a/test/jest/unit/lib/iac/test/v2/analytics/index.spec.ts b/test/jest/unit/lib/iac/test/v2/analytics/index.spec.ts index 01a20ddf79..49788d6330 100644 --- a/test/jest/unit/lib/iac/test/v2/analytics/index.spec.ts +++ b/test/jest/unit/lib/iac/test/v2/analytics/index.spec.ts @@ -1,10 +1,11 @@ import * as clonedeep from 'lodash.clonedeep'; import * as path from 'path'; +import * as analytics from '../../../../../../../../src/lib/analytics'; import * as fs from 'fs'; import { SnykIacTestOutput } from '../../../../../../../../src/lib/iac/test/v2/scan/results'; import { - computeIacAnalytics, + addIacAnalytics, IacAnalytics, } from '../../../../../../../../src/lib/iac/test/v2/analytics'; @@ -44,15 +45,24 @@ describe('computeIacAnalytics', () => { ), ); - it('generates the correct analytics', async () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('sends the expected analytics', async () => { // Arrange + const addedAnalytics: Record = {}; + jest.spyOn(analytics, 'add').mockImplementation((key, value) => { + addedAnalytics[key] = value; + }); + const testOutput = clonedeep(snykIacTestOutputFixture); const expectedAnalytics = clonedeep(iacAnalyticsFixture); // Act - const result = computeIacAnalytics(testOutput); + addIacAnalytics(testOutput); // Assert - expect(result).toStrictEqual(expectedAnalytics); + expect(addedAnalytics).toStrictEqual(expectedAnalytics); }); }); From 83894c808e9d612f0ba187caceb875332b4dd9ac Mon Sep 17 00:00:00 2001 From: Ofek Atar Date: Wed, 28 Sep 2022 14:42:55 +0300 Subject: [PATCH 55/55] chore: Increase IaC smoke test timeout to 120 seconds --- .github/workflows/iac-smoke-tests.yml | 3 +-- packages/iac-cli-alert/src/index.ts | 11 ++--------- test/smoke/iac/test.spec.ts | 2 +- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/.github/workflows/iac-smoke-tests.yml b/.github/workflows/iac-smoke-tests.yml index 3ef2710a10..a128707f06 100644 --- a/.github/workflows/iac-smoke-tests.yml +++ b/.github/workflows/iac-smoke-tests.yml @@ -78,7 +78,7 @@ jobs: trigger_iac_cli_alert: name: Alert for failed IaC smoke tests needs: [run_iac_smoke_tests] - if: ${{ failure() && !inputs.is_skip_alert && needs.run_iac_smoke_tests.result == 'failures' }} + if: ${{ failure() && !inputs.is_skip_alert && needs.run_iac_smoke_tests.result == 'failure' }} runs-on: ubuntu-latest defaults: run: @@ -95,4 +95,3 @@ jobs: - run: npm start env: IAC_SMOKE_TESTS_SLACK_WEBHOOK_URL: ${{ secrets.IAC_SMOKE_TESTS_SLACK_WEBHOOK_URL }} - IAC_SMOKE_TESTS_OS: ${{ matrix.os }} diff --git a/packages/iac-cli-alert/src/index.ts b/packages/iac-cli-alert/src/index.ts index fca92a3424..85e9e1c9d2 100644 --- a/packages/iac-cli-alert/src/index.ts +++ b/packages/iac-cli-alert/src/index.ts @@ -10,23 +10,16 @@ if (!process.env.IAC_SMOKE_TESTS_SLACK_WEBHOOK_URL) { process.exit(1); } -if (!process.env.IAC_SMOKE_TESTS_OS) { - console.error('Missing the IAC_SMOKE_TESTS_OS environment variable'); - process.exit(1); -} - const IAC_SMOKE_TESTS_SLACK_WEBHOOK_URL = process.env.IAC_SMOKE_TESTS_SLACK_WEBHOOK_URL; -const IAC_SMOKE_TESTS_OS = process.env.IAC_SMOKE_TESTS_OS; const slackWebhook = new IncomingWebhook(IAC_SMOKE_TESTS_SLACK_WEBHOOK_URL); async function sendSlackAlert() { console.log('IaC smoke tests failed. Sending Slack alert...'); const args: IncomingWebhookDefaultArguments = { - username: 'IaC CLI Alerts', - text: `An Infrastructure as Code Smoke Tests job failed. \n Operating system - ${IAC_SMOKE_TESTS_OS} \n`, - icon_emoji: 'snyk-iac', + text: + 'An Infrastructure as Code Smoke Tests job failed. \n', }; await slackWebhook.send(args); console.log('Slack alert sent.'); diff --git a/test/smoke/iac/test.spec.ts b/test/smoke/iac/test.spec.ts index 0e6253c2f6..5d9eba3db9 100644 --- a/test/smoke/iac/test.spec.ts +++ b/test/smoke/iac/test.spec.ts @@ -1,6 +1,6 @@ import { run } from '../../jest/acceptance/iac/helpers'; -jest.setTimeout(1_000 * 90); +jest.setTimeout(1_000 * 120); describe('snyk iac test --experimental', () => { beforeAll(async () => {