diff --git a/.auditrc b/.auditrc new file mode 100644 index 00000000..e17295fa --- /dev/null +++ b/.auditrc @@ -0,0 +1,14 @@ +exports.exceptions = [ + // Severity: low, moment (< 2.19.3), currently used by react-dates + "https://npmjs.com/advisories/532", + + // Severity: low, lodash (< 4.17.5), used heavily in our CRA fork + "https://npmjs.com/advisories/577", + + // Severity: low, merge (< 1.2.1), used by Jest (CRA fork) + "https://npmjs.com/advisories/722", + + // Severity: high, webpack-dev-server (< 3.1.10), (CRA fork) + // Note: don't run webpack-dev-server on public web. + "https://npmjs.com/advisories/725", +]; diff --git a/.circleci/config.yml b/.circleci/config.yml index 4c1ca3e9..ba44aee3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -69,6 +69,29 @@ jobs: - run: name: Build client application command: yarn run build + audit: + docker: + - image: circleci/node:10.14 + steps: + - checkout + - restore_cache: + name: Restore Yarn Package Cache + keys: + - yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }} + - yarn-packages-{{ .Branch }} + - yarn-packages-master + - yarn-packages- + - run: + name: Install Dependencies + command: yarn install + - save_cache: + name: Save Yarn Package Cache + key: yarn-packages-{{ .Branch }}-{{ checksum "yarn.lock" }} + paths: + - node_modules/ + - run: + name: Audit dependencies + command: yarn run audit workflows: version: 2 format_test_build_audit: @@ -76,3 +99,4 @@ workflows: - format - test - build + - audit diff --git a/.nsprc b/.nsprc deleted file mode 100644 index eb9adf46..00000000 --- a/.nsprc +++ /dev/null @@ -1,10 +0,0 @@ -{ - "exceptions": [ - "https://nodesecurity.io/advisories/532", - "https://nodesecurity.io/advisories/157", - "https://nodesecurity.io/advisories/577", - "https://nodesecurity.io/advisories/654", - "https://nodesecurity.io/advisories/664", - "https://nodesecurity.io/advisories/678" - ] -} diff --git a/CHANGELOG.md b/CHANGELOG.md index 0582ed2c..7244ae24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,9 @@ way to update this template, but currently, we follow a pattern: ## [v2.10.0] 2019-01-31 +- [add] Add audit script and include it as a CI job. We had security audit job previously on top of + node security platform (nsp), but that service was closed on December 2018. + [#1020](https://github.com/sharetribe/flex-template-web/pull/1020) - [change] Extracted and refactored utility functions related to transaction and refactored several components that show transaction data (incl. InboxPage, TransactionPanel, ActivityFeed). Before updating your customization project, you should read more about what has changed from the pull diff --git a/package.json b/package.json index 71bdccf5..e2b72503 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "url": "^0.11.0" }, "devDependencies": { + "bfj": "^6.1.1", "chalk": "^2.4.1", "enzyme": "^3.7.0", "enzyme-adapter-react-16": "^1.7.0", @@ -65,6 +66,7 @@ "prettier": "^1.15.3" }, "scripts": { + "audit": "yarn audit --json | node scripts/audit.js", "clean": "rm -rf build/*", "config": "node scripts/config.js", "dev": "node scripts/config.js --check && sharetribe-scripts start", diff --git a/scripts/audit.js b/scripts/audit.js new file mode 100644 index 00000000..e732987d --- /dev/null +++ b/scripts/audit.js @@ -0,0 +1,79 @@ +// Check possible npm dependency vulnerabilities +// Usage: execute "yarn run audit" in the shell +// +// You can add exceptions through .nsprc file, which is a hidden file in root folder. +// +// Note: to use this script, you should pipe in the output of 'yarn audit --json' + +const bfj = require('bfj'); +const fs = require('fs'); +const exceptions = require('../.auditrc').exceptions; + +const INDENT = ' '; +const isAuditAdvisory = o => o.type === 'auditAdvisory'; + +// get an advisory or empty object +const getAdvisory = o => (!o ? {} : !o.data ? {} : !o.data.advisory ? {} : o.data.advisory); +// get a resolution or empty object +const getResolution = o => (!o ? {} : !o.data ? {} : !o.data.resolution ? {} : o.data.resolution); + +// Read the output of 'yarn audit --json', which should be piped in through stdin +const stdinStream = process.stdin.resume(); +let advisories = {}; +bfj + .match(stdinStream, (key, value, depth) => depth === 0, { ndjson: true }) + .on('data', object => { + if (isAuditAdvisory(object) && Array.isArray(exceptions)) { + const { id, severity, title, url } = getAdvisory(object); + const { path } = getResolution(object); + const isInExceptionList = url && exceptions.includes(url); + + if (!isInExceptionList && url && path) { + const advisory = advisories[id] ? advisories[id] : { url, severity, title }; + const paths = advisory.paths ? advisory.paths : []; + advisories[id] = { ...advisory, paths: paths.concat(path) }; + } + } + }) + .on('dataError', error => { + // A syntax error was found in the JSON + console.error( + `An error occurred while processing data. + You need to pipe the results of "yarn audit --json" to this script from shell. + Error`, + error + ); + process.exit(1); + }) + .on('error', error => { + // Some kind of operational error occurred + console.error( + `An error occurred while processing data. + You need to pipe the results of "yarn audit --json" to this script from shell. + Error`, + error + ); + process.exit(1); + }) + .on('end', error => { + const advisoryKeys = Object.keys(advisories); + if (advisoryKeys.length > 0) { + console.log('Vulneralibilities found:'); + console.log('\n----------------------------------------\n'); + + advisoryKeys.forEach(key => { + const { title, severity, url, paths } = advisories[key]; + console.log(key, `(${title})`); + console.log('Severity:', severity); + console.log('More info:', url); + console.log('Affected dependencies:'); + paths.forEach(path => { + console.log(INDENT, path); + }); + console.log('\n----------------------------------------\n'); + }); + process.exit(1); + } else { + process.exit(); + } + }); diff --git a/yarn.lock b/yarn.lock index 6d748f14..d224fb9f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1220,6 +1220,16 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +bfj@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/bfj/-/bfj-6.1.1.tgz#05a3b7784fbd72cfa3c22e56002ef99336516c48" + integrity sha512-+GUNvzHR4nRyGybQc2WpNJL4MJazMuvf92ueIyA0bIkPRwhhQu3IfZQ2PSoVPpCBJfmoSdOxu5rnotfFLlvYRQ== + dependencies: + bluebird "^3.5.1" + check-types "^7.3.0" + hoopy "^0.1.2" + tryer "^1.0.0" + big.js@^3.1.3: version "3.2.0" resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" @@ -1232,6 +1242,11 @@ bluebird@^3.4.7: version "3.5.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.2.tgz#1be0908e054a751754549c270489c1505d4ab15a" +bluebird@^3.5.1: + version "3.5.3" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" + integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== + bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" @@ -1610,6 +1625,11 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +check-types@^7.3.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/check-types/-/check-types-7.4.0.tgz#0378ec1b9616ec71f774931a3c6516fad8c152f4" + integrity sha512-YbulWHdfP99UfZ73NcUDlNJhEIDgm9Doq9GhpyXbF+7Aegi3CVV7qqMCKTTqJxlvEvnQBp9IA+dxsGN6xK/nSg== + cheerio@^1.0.0-rc.2: version "1.0.0-rc.2" resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db" @@ -3821,6 +3841,11 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" +hoopy@^0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" + integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ== + hosted-git-info@^2.1.4: version "2.5.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" @@ -8380,6 +8405,11 @@ trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" +tryer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" + integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== + tslib@^1.9.0, tslib@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"