diff --git a/config.schema.json b/config.schema.json index 771e83d0c..a4072b97a 100644 --- a/config.schema.json +++ b/config.schema.json @@ -8,6 +8,7 @@ "proxyUrl": { "type": "string" }, "cookieSecret": { "type": "string" }, "sessionMaxAgeHours": { "type": "number" }, + "dependencyVulnThreshold": { "type": "string" }, "api": { "description": "Third party APIs", "type": "object" diff --git a/package-lock.json b/package-lock.json index 94d54c80f..224f28c61 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,8 @@ "./packages/git-proxy-cli" ], "dependencies": { + "@finos/check-dependency-vulnerabilities": "file:plugins/check-dependency-vulnerabilities/finos-check-dependency-vulnerabilities-0.1.0-alpha.0.tgz", + "@finos/git-proxy-plugin-samples": "file:plugins/git-proxy-plugin-samples/finos-git-proxy-plugin-samples-0.1.0.tgz", "@material-ui/core": "^4.11.0", "@material-ui/icons": "4.11.3", "@primer/octicons-react": "^19.8.0", @@ -2247,14 +2249,95 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@finos/check-dependency-vulnerabilities": { + "version": "0.1.0-alpha.0", + "resolved": "file:plugins/check-dependency-vulnerabilities/finos-check-dependency-vulnerabilities-0.1.0-alpha.0.tgz", + "integrity": "sha512-w0YGWzMQao4mKkqHH1LBd4+ic4cX/p0iyIWIJJiGLHC+xbrMM7NkUcgkrHD+iC248L5oChKPQw+cNyAB0QFqRA==", + "license": "Apache-2.0", + "dependencies": { + "express": "^4.18.2" + }, + "peerDependencies": { + "@finos/git-proxy": "^1.4.0" + } + }, "node_modules/@finos/git-proxy": { - "resolved": "", - "link": true + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@finos/git-proxy/-/git-proxy-1.7.0.tgz", + "integrity": "sha512-mA8ypTTrKeTmpj4kkOFB4n+nfMfTEovqZ7GBmD8CIIPwkmSRc0S8T08SArKtoCToKj4Y53L5eemI1thWZn15Jw==", + "license": "Apache-2.0", + "peer": true, + "workspaces": [ + "./packages/git-proxy-cli" + ], + "dependencies": { + "@material-ui/core": "^4.11.0", + "@material-ui/icons": "4.11.3", + "@primer/octicons-react": "^19.8.0", + "@seald-io/nedb": "^4.0.2", + "axios": "^1.6.0", + "bcryptjs": "^2.4.3", + "bit-mask": "^1.0.2", + "body-parser": "^1.20.1", + "classnames": "2.5.1", + "concurrently": "^8.0.0", + "connect-mongo": "^5.1.0", + "cors": "^2.8.5", + "diff2html": "^3.4.33", + "express": "^4.18.2", + "express-http-proxy": "^2.0.0", + "express-rate-limit": "^7.1.5", + "express-session": "^1.17.1", + "history": "5.3.0", + "isomorphic-git": "^1.27.1", + "jsonschema": "^1.4.1", + "load-plugin": "^6.0.0", + "lodash": "^4.17.21", + "lusca": "^1.7.0", + "moment": "^2.29.4", + "mongodb": "^5.0.0", + "nodemailer": "^6.6.1", + "parse-diff": "^0.11.1", + "passport": "^0.7.0", + "passport-activedirectory": "^1.0.4", + "passport-local": "^1.0.0", + "perfect-scrollbar": "^1.5.5", + "prop-types": "15.8.1", + "react": "^16.13.1", + "react-dom": "^16.13.1", + "react-html-parser": "^2.0.2", + "react-router-dom": "6.26.2", + "simple-git": "^3.25.0", + "uuid": "^10.0.0", + "yargs": "^17.7.2" + }, + "bin": { + "git-proxy": "index.js", + "git-proxy-all": "concurrently 'npm run server' 'npm run client'" + }, + "optionalDependencies": { + "@esbuild/darwin-arm64": "^0.18.20", + "@esbuild/darwin-x64": "^0.23.0", + "@esbuild/linux-x64": "0.23.0", + "@esbuild/win32-x64": "0.23.0" + } }, "node_modules/@finos/git-proxy-cli": { "resolved": "packages/git-proxy-cli", "link": true }, + "node_modules/@finos/git-proxy-plugin-samples": { + "version": "0.1.0", + "resolved": "file:plugins/git-proxy-plugin-samples/finos-git-proxy-plugin-samples-0.1.0.tgz", + "integrity": "sha512-opq+YGgHf9Qh2JYLotQ1iS2ByBTLfwkRmZtwFndeGSzvfZ7kiv2IaS57nmVQfNvXHB0AZZJyHaJiiUYF0vP/iQ==", + "license": "Apache-2.0", + "dependencies": { + "express": "^4.18.2" + }, + "peerDependencies": { + "@finos/git-proxy": "1.7.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -4149,6 +4232,13 @@ "node": "*" } }, + "node_modules/async-lock": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz", + "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==", + "license": "MIT", + "peer": true + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -4705,6 +4795,13 @@ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" }, + "node_modules/clean-git-ref": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz", + "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==", + "license": "Apache-2.0", + "peer": true + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -5233,6 +5330,19 @@ "typescript": ">=4" } }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -5654,6 +5764,22 @@ "node": ">=0.10.0" } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/deep-eql": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", @@ -5787,6 +5913,13 @@ "highlight.js": "11.9.0" } }, + "node_modules/diff3": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", + "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==", + "license": "MIT", + "peer": true + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -7882,7 +8015,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", - "dev": true, "engines": { "node": ">= 4" } @@ -8525,6 +8657,43 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "node_modules/isomorphic-git": { + "version": "1.27.2", + "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.27.2.tgz", + "integrity": "sha512-nCiz+ieOkWb5kDJSSckDTiMjTcgkxqH2xuiQmw1Y6O/spwx4d6TKYSfGCd4f71HGvUYcRSUGqJEI+3uN6UQlOw==", + "license": "MIT", + "peer": true, + "dependencies": { + "async-lock": "^1.4.1", + "clean-git-ref": "^2.0.1", + "crc-32": "^1.2.0", + "diff3": "0.0.3", + "ignore": "^5.1.4", + "minimisted": "^2.0.0", + "pako": "^1.0.10", + "path-browserify": "^1.0.1", + "pify": "^4.0.1", + "readable-stream": "^3.4.0", + "sha.js": "^2.4.9", + "simple-get": "^4.0.1" + }, + "bin": { + "isogit": "cli.cjs" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/isomorphic-git/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -9696,6 +9865,19 @@ "node": ">= 0.6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -9717,11 +9899,20 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minimisted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", + "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", + "license": "MIT", + "peer": true, + "dependencies": { + "minimist": "^1.2.5" + } + }, "node_modules/minipass": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", @@ -10607,6 +10798,13 @@ "node": ">=8" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)", + "peer": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -10712,6 +10910,13 @@ "node": ">= 0.4.0" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "license": "MIT", + "peer": true + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -11762,6 +11967,20 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "license": "(MIT AND BSD-3-Clause)", + "peer": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -11818,6 +12037,53 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "peer": true + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/simple-git": { "version": "3.27.0", "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.27.0.tgz", @@ -13416,6 +13682,10 @@ "devDependencies": { "chai": "^4.2.0" } + }, + "packages/git-proxy-cli/node_modules/@finos/git-proxy": { + "resolved": "", + "link": true } } } diff --git a/package.json b/package.json index 05a1b08db..4492a34f5 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,8 @@ "url": "https://github.com/finos/git-proxy" }, "dependencies": { + "@finos/check-dependency-vulnerabilities": "file:plugins/check-dependency-vulnerabilities/finos-check-dependency-vulnerabilities-0.1.0-alpha.0.tgz", + "@finos/git-proxy-plugin-samples": "file:plugins/git-proxy-plugin-samples/finos-git-proxy-plugin-samples-0.1.0.tgz", "@material-ui/core": "^4.11.0", "@material-ui/icons": "4.11.3", "@primer/octicons-react": "^19.8.0", diff --git a/plugins/check-dependency-vulnerabilities/README.md b/plugins/check-dependency-vulnerabilities/README.md new file mode 100644 index 000000000..135d1ae8f --- /dev/null +++ b/plugins/check-dependency-vulnerabilities/README.md @@ -0,0 +1,15 @@ + + +Plugin that checks if any vulnerable dependency is used in a git repo. Uses OWASP's dependency-check to achieve this. +The filtering strictness of the plugin can be decided by the user by using the "dependencyVulnThreshold" key in config JSON. "dependencyVulnThreshold" decides the lower bound to the filtering. So, if "dependencyVulnThreshold" is "LOW", any vulnerabilities of level LOW or higher would block the push. Allowed values for dependencyVulnThreshold are info, low, medium, high, critical + +Check this link to see the languages/file-types supported by dependency check +https://jeremylong.github.io/DependencyCheck/analyzers/index.html + +## Pre Requisites +This plugin expects dependency-check to be installed and in the path environment variable +Command `dependency-check --updateonly` has to be run once in the terminal after dependency-check installation + +## Limitations +dependency-check is using an argument --noupdate to avoid the execution time overhead(~20-30 minutes), which comes with automatic updation of NVD (National Vulnerability Database). This means user has to manually run the update command atleast once during the initial set-up and later whenever user wants to use the latest data. + diff --git a/plugins/check-dependency-vulnerabilities/checkDependencyVuln.js b/plugins/check-dependency-vulnerabilities/checkDependencyVuln.js new file mode 100644 index 000000000..394a65737 --- /dev/null +++ b/plugins/check-dependency-vulnerabilities/checkDependencyVuln.js @@ -0,0 +1,163 @@ +/* +** Plugin that checks if any vulnerable dependency is used in a git repo +** Uses OWASP's dependency-check to achieve this +** The filtering strictness of the plugin can be decided by the user +** by using the "dependencyVulnThreshold" key in config JSON. +** "dependencyVulnThreshold" decides the lower bound to the filtering. +** So, if "dependencyVulnThreshold" is "LOW", any vulnerabilities of level LOW or higher +** would block the push +** Allowed values for dependencyVulnThreshold are info, low, medium, high, critical +** NOTE: This plugin expects dependency-check to be installed and in the +** path environment variable +*/ + +import { PushActionPlugin } from "@finos/git-proxy/src/plugin.js"; +import { Step } from "@finos/git-proxy/src/proxy/actions/index.js"; +import pkg from "@finos/git-proxy/src/config/file.js"; + +import child from "child_process"; +import { createTempRepo, deleteTempRepo } from "./temporaryRepo.js"; +import fs from "fs"; +import path from "path"; + +class checkDependencyVulnPlugin extends PushActionPlugin { + constructor() { + super(function logMessage(req, action) { + + // Default Severity + let configMinSeverity = "HIGH"; + + const severityLevels = { + "critical": 5, + "high": 4, + "severe": 4, + "medium": 3, + "moderate": 3, + "low": 2, + "info": 1 + }; + + try { + const { configFile } = pkg; + const configPath = configFile; + const configData = fs.readFileSync(configPath, 'utf8'); + const config = JSON.parse(configData); + if (config["dependencyVulnThreshold"]) { + configMinSeverity = config["dependencyVulnThreshold"]; + } + } + catch (error) { + console.warn("Failed to read vulnerability config file. Going with default options"); + } + + const dirPath = createTempRepo(req, action); + + + const step = new Step('checkDependencyVulnPlugin'); + + let commitFrom = `4b825dc642cb6eb9a060e54bf8d69288fbee4904`; + + if (action.commitFrom === '0000000000000000000000000000000000000000') { + if (action.commitData[0].parent !== '0000000000000000000000000000000000000000') { + commitFrom = `${action.commitData[action.commitData.length - 1].parent}`; + } + } else { + commitFrom = `${action.commitFrom}`; + } + + const file_names = child.spawnSync('git', ['diff', '--name-only', action.commitTo, commitFrom], { + cwd: dirPath, + encoding: 'utf-8', + maxBuffer: 50 * 1024 * 1024, + }).stdout; + + // Split the output by new lines and filter out any empty entries + const filesArray = file_names.split('\n').filter(file => file.trim() !== ''); + + console.log('Changed files:', filesArray); + + const outputdirPath = path.join(dirPath, 'output'); + + if (!fs.existsSync(outputdirPath)) { + fs.mkdirSync(outputdirPath); + } + + for (let filesToScan of filesArray) { + // Change to the temporary directory and checkout package.json + console.log('Printing filesToScan Variable :', filesToScan); + console.log('Printing dirPath :', dirPath); + + const showResult = child.spawnSync('git', ['show', 'HEAD:' + filesToScan], { + cwd: dirPath, + encoding: 'utf-8', + maxBuffer: 50 * 1024 * 1024 + }); + + const fileName = path.join(outputdirPath, filesToScan); + if (showResult.stderr) { + console.error('Error executing git command:', showResult.stderr); + } else { + fs.writeFileSync(fileName, showResult.stdout); + } + } + + const dependencyCheckRes = + child.spawnSync( + 'dependency-check', ['--noupdate', '--project', 'Git-Proxy-Dependency-Check', + '--scan', outputdirPath, '--format', 'JSON', '--out', dirPath], { + cwd: './', + shell: true, + encoding: 'utf-8', + maxBuffer: 50 * 1024 * 1024 + }); + + // Load the JSON report generated by OWASP Dependency-Check + const reportPath = `./${dirPath}/dependency-check-report.json`; + try { + const data = fs.readFileSync(reportPath, 'utf8'); + const report = JSON.parse(data); + + // Filter all vulnerabilities that have "high" severity (case-insensitive) + const vulnerabilities = report.dependencies.flatMap(dep => + (Array.isArray(dep.vulnerabilities) ? dep.vulnerabilities : []) + .filter(vuln => vuln.severity + && ((severityLevels[vuln.severity.toLowerCase()] || 4) >= (severityLevels[configMinSeverity.toLowerCase()] || 0))).map( + vuln => ({ + fileName: dep.fileName, + })) + ); + + // Count the high vulnerabilities + const vulnerabilityCount = vulnerabilities.length; + + console.log(`Total Vulnerabilities: ${vulnerabilityCount}`); + + if (vulnerabilityCount > 0) { + const dependenciesString = vulnerabilities + .map(vuln => `${vuln.fileName}`) + .join(', '); // Join all dependencies into a single string with commas + + step.blocked = true; + step.blockedMessage = `Found dependencies with vulnerabilities : ${dependenciesString}`; + action.allowPush = false; + } else { + console.log('No vulnerabilities found.'); + } + + action.addStep(step); + + return action; + + } catch (parseError) { + console.error('Error parsing the JSON report:'); + return action; + } finally { + deleteTempRepo(dirPath); + }; + + }) + } +} + +// Default exports are supported and will be loaded by the plugin loader +export default new checkDependencyVulnPlugin(); diff --git a/plugins/check-dependency-vulnerabilities/package.json b/plugins/check-dependency-vulnerabilities/package.json new file mode 100644 index 000000000..82d6474b4 --- /dev/null +++ b/plugins/check-dependency-vulnerabilities/package.json @@ -0,0 +1,20 @@ +{ + "name": "@finos/check-dependency-vulnerabilities", + "version": "0.1.0-alpha.0", + "description": "Plugin to check dependencies for vulnerable packages", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Kavya", + "license": "Apache-2.0", + "type": "module", + "exports": { + ".": "./checkDependencyVuln.js" + }, + "dependencies": { + "express": "^4.18.2" + }, + "peerDependencies": { + "@finos/git-proxy": "^1.4.0" + } +} \ No newline at end of file diff --git a/plugins/check-dependency-vulnerabilities/temporaryRepo.js b/plugins/check-dependency-vulnerabilities/temporaryRepo.js new file mode 100644 index 000000000..92bfac8fa --- /dev/null +++ b/plugins/check-dependency-vulnerabilities/temporaryRepo.js @@ -0,0 +1,42 @@ +import { spawnSync } from "child_process"; +import fs from "fs"; + +const dir = './.tempRepo'; + +export const createTempRepo = (req, action) => { + const tempRepoPush_dir = `${dir}/${action.timestamp}`; + + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir); + } + + if (!fs.existsSync(tempRepoPush_dir)) { + fs.mkdirSync(tempRepoPush_dir, '0777', true); + } + + const cmnd = `git clone ${action.url} --bare`; + + const response = spawnSync('git', ['clone', action.url, '--bare', '--progress'], { + cwd: tempRepoPush_dir, + encoding: 'utf-8', + }); + + const cmd = `git receive-pack ${action.repoName}`; + + const content = spawnSync('git', ['receive-pack', action.repoName], { + cwd: tempRepoPush_dir, + input: req.body, + encoding: 'utf-8', + }).stdout; + + return `${dir}/${action.timestamp}/${action.repoName}`; +} + +export const deleteTempRepo = () => { + fs.rm(dir, { recursive: true, force: true }, (err) => { + if (err) { + throw err; + } + console.log(`.tempRepo is deleted!`); + }); +} \ No newline at end of file