diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index d08f5ab9..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,59 +0,0 @@ -env_defaults: &env_defaults - working_directory: ~ - docker: - - image: circleci/node:10.16 - -version: 2.1 -jobs: - build: - <<: *env_defaults - steps: - - checkout - - # Download and cache dependencies - - restore_cache: - keys: - - v1.0-dependencies-{{ checksum "package.json" }} - # fallback to using the latest cache if no exact match is found - - v1.0-dependencies- - - - run: npm install - - - save_cache: - paths: - - node_modules - key: v1.0-dependencies-{{ checksum "package.json" }} - - - persist_to_workspace: - root: . - paths: - - node_modules - - lint: - <<: *env_defaults - steps: - - checkout - - attach_workspace: - at: . - - run: npm run lint - - test: - <<: *env_defaults - steps: - - checkout - - attach_workspace: - at: . - - run: npm test - -workflows: - version: 2 - - build-lint-test: - jobs: - - build - - lint: - requires: - - build - - test: - requires: - - build diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..3f3646cb --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,23 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 5 + target-branch: "dev" + allow: + - dependency-name: "synthetix-*" + dependency-type: "production" + - dependency-name: "@synthetixio/*" + dependency-type: "production" + labels: + - "npm" + - "dependencies" + pull-request-branch-name: + separator: "-" diff --git a/.github/workflows/audit_lint_build.yml b/.github/workflows/audit_lint_build.yml new file mode 100644 index 00000000..77dfd92f --- /dev/null +++ b/.github/workflows/audit_lint_build.yml @@ -0,0 +1,81 @@ +name: Synthetix Exchange CI + +on: + push: + pull_request: + branches: [master, dev] + +jobs: + audit: + # run only on master/dev branch and pull requests + if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev' || github.event_name == 'pull_request' + runs-on: ubuntu-latest + + container: + image: ghcr.io/synthetixio/docker-sec-tools/base:12.19 + credentials: + username: synthetixio + password: ${{ secrets.GH_PACKAGES_READ_ONLY }} + + steps: + - name: Checkout + uses: actions/checkout@ee5a9d1395988d7c82c67c69571871f5994b94df # pin@v2 + + - name: Audit dependencies + run: audit-ci --critical --report-type important + + - name: Lockfile lint + run: lockfile-lint -p package-lock.json --type npm --allowed-hosts npm github.com --allowed-schemes "https:" "git+https:" + + build: + needs: audit + # run only on audit success or audit skipped + if: always() && (needs.audit.result == 'success' || needs.audit.result == 'skipped') + runs-on: ubuntu-latest + + container: + image: ghcr.io/synthetixio/docker-node/alpine:12.19 + credentials: + username: synthetixio + password: ${{ secrets.GH_PACKAGES_READ_ONLY }} + + steps: + - name: Checkout + uses: actions/checkout@ee5a9d1395988d7c82c67c69571871f5994b94df # pin@v2 + + - name: Cache node modules + uses: actions/cache@3b70782066bd817837b6bd8c518d45b54d91bf76 # pin@v2 + with: + path: | + .npm + node_modules + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + ${{ runner.os }}- + continue-on-error: true + + - name: Install dependencies + run: npm install --no-audit + + - name: Lint + # run only on master/dev branch and pull requests + if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev' || github.event_name == 'pull_request' + run: npm run lint:sarif + + - name: Upload lint results + # run if lint failed and only on master/dev branch and pull requests + if: always() && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev' || github.event_name == 'pull_request') + uses: github/codeql-action/upload-sarif@b1e2c9b8bd0550a90e66c967d9795316f9f21910 # pin@codeql-bundle-20201008 + with: + sarif_file: lint-results.sarif + continue-on-error: true + + - name: Build + run: npm run build + + - name: Archive artifacts + if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev' || github.event_name == 'pull_request' + uses: actions/upload-artifact@726a6dcd0199f578459862705eed35cda05af50b # pin@v2 + with: + path: build diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..940ade9c --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,38 @@ +name: CodeQL + +on: + push: + branches: [master, dev] + paths-ignore: + - node_modules + pull_request: + branches: [master, dev] + paths-ignore: + - node_modules + schedule: + - cron: '0 6 * * 3' + +jobs: + analyze: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@ee5a9d1395988d7c82c67c69571871f5994b94df # pin@v2 + with: + fetch-depth: 2 + + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + queries: security-and-quality + languages: javascript + + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.gitignore b/.gitignore index f200ea5a..63dba0c1 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ yarn-error.log* .yalc yalc.lock + +lint-results.sarif diff --git a/package-lock.json b/package-lock.json index e00c846e..022b9c82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1193,15 +1193,6 @@ "resolved": "https://registry.npmjs.org/@bugsnag/plugin-react/-/plugin-react-6.2.0.tgz", "integrity": "sha512-JI56D3ZhXGjH5UqeSTltdxVTPjMpfNI/Vd5XP0V/gBAJb6CeILX3hLe5G1VmxxZciVNEfG5724YKgadqp6/uWg==" }, - "@chainlink/contracts-0.0.10": { - "version": "npm:@chainlink/contracts@0.0.10", - "resolved": "https://registry.npmjs.org/@chainlink/contracts/-/contracts-0.0.10.tgz", - "integrity": "sha512-ok+ucSQ+3mrR+zjbi6zIrdd5M9XymcqVcnXGVyqBVRYZp97jS2/rt/glP320JmHxmi4pacgDOg0Ux11xIr1S8Q==", - "requires": { - "@truffle/contract": "^4.2.6", - "ethers": "^4.0.45" - } - }, "@cnakazawa/watch": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", @@ -2137,6 +2128,19 @@ "react-is": "^16.8.0" } }, + "@microsoft/eslint-formatter-sarif": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@microsoft/eslint-formatter-sarif/-/eslint-formatter-sarif-2.1.5.tgz", + "integrity": "sha512-WnA/25mx20xuFXILwevcxegb2xnubcBLjaLXm0++J/7+4o+nwnVPbMzViMd32r5Ccquod5NVg62/iy9nvqZHEQ==", + "dev": true, + "requires": { + "chai": "^4.2.0", + "jschardet": "^2.2.1", + "lodash": "^4.17.14", + "mocha": "^5.2.0", + "utf8": "^3.0.0" + } + }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", @@ -7040,6 +7044,12 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -8967,6 +8977,12 @@ } } }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", @@ -9380,6 +9396,20 @@ "integrity": "sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==", "dev": true }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -9425,6 +9455,12 @@ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, "checkpoint-store": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/checkpoint-store/-/checkpoint-store-1.1.0.tgz", @@ -10826,6 +10862,15 @@ "mimic-response": "^1.0.0" } }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-equal": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", @@ -11069,6 +11114,12 @@ } } }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, "diff-sequences": { "version": "24.9.0", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", @@ -13824,6 +13875,12 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, "get-own-enumerable-property-symbols": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", @@ -14064,6 +14121,12 @@ "iterall": "^1.2.2" } }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, "growly": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", @@ -15937,6 +16000,12 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, + "jschardet": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-2.2.1.tgz", + "integrity": "sha512-Ks2JNuUJoc7PGaZ7bVFtSEvOcr0rBq6Q1J5/7+zKWLT+g+4zziL63O0jg7y2jxhzIa1LVsHUbPXrbaWmz9iwDw==", + "dev": true + }, "jsdom": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", @@ -17389,6 +17458,92 @@ "mkdirp": "*" } }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + }, + "dependencies": { + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "mock-fs": { "version": "4.13.0", "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.13.0.tgz", @@ -18106,11 +18261,6 @@ } } }, - "openzeppelin-solidity-2.3.0": { - "version": "npm:openzeppelin-solidity@2.3.0", - "resolved": "https://registry.npmjs.org/openzeppelin-solidity/-/openzeppelin-solidity-2.3.0.tgz", - "integrity": "sha512-QYeiPLvB1oSbDt6lDQvvpx7k8ODczvE474hb2kLXZBPKMsxKT1WxTCHBYrCU7kS7hfAku4DcJ0jqOyL+jvjwQw==" - }, "opn": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", @@ -18437,6 +18587,12 @@ "pify": "^3.0.0" } }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, "pbkdf2": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", @@ -23641,10 +23797,24 @@ "web3-utils": "1.2.2" }, "dependencies": { + "@chainlink/contracts-0.0.10": { + "version": "npm:@chainlink/contracts@0.0.10", + "resolved": "https://registry.npmjs.org/@chainlink/contracts/-/contracts-0.0.10.tgz", + "integrity": "sha512-ok+ucSQ+3mrR+zjbi6zIrdd5M9XymcqVcnXGVyqBVRYZp97jS2/rt/glP320JmHxmi4pacgDOg0Ux11xIr1S8Q==", + "requires": { + "@truffle/contract": "^4.2.6", + "ethers": "^4.0.45" + } + }, "commander": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==" + }, + "openzeppelin-solidity-2.3.0": { + "version": "npm:openzeppelin-solidity@2.3.0", + "resolved": "https://registry.npmjs.org/openzeppelin-solidity/-/openzeppelin-solidity-2.3.0.tgz", + "integrity": "sha512-QYeiPLvB1oSbDt6lDQvvpx7k8ODczvE474hb2kLXZBPKMsxKT1WxTCHBYrCU7kS7hfAku4DcJ0jqOyL+jvjwQw==" } } }, @@ -24325,6 +24495,12 @@ "prelude-ls": "~1.1.2" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", diff --git a/package.json b/package.json index 20ba66b5..48218977 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "use-immer": "0.4.0" }, "devDependencies": { + "@microsoft/eslint-formatter-sarif": "2.1.5", "@storybook/addon-actions": "^5.3.18", "@storybook/addon-backgrounds": "^5.3.18", "@storybook/addon-knobs": "^5.3.18", @@ -89,6 +90,7 @@ "lint:fix": "eslint --fix './src/**/*.{js,ts,tsx}'", "lint:css": "stylelint './src/**/*.{js,ts,tsx}'", "lint": "eslint './src/**/*.{js,ts,tsx}' && tsc", + "lint:sarif": "node scripts/lint.js './src/**/*.{js,ts,tsx}' && tsc", "storybook": "start-storybook -p 6006", "build-storybook": "build-storybook" }, diff --git a/scripts/lint.js b/scripts/lint.js new file mode 100644 index 00000000..1b120be4 --- /dev/null +++ b/scripts/lint.js @@ -0,0 +1,37 @@ +const fs = require('fs'); +const CLIEngine = require('eslint').CLIEngine; + +const argv = process.argv.slice(2); +const cli = new CLIEngine({ + fix: false, + useEslintrc: true, +}); + +console.log('Starting to lint..'); + +// Lint all files +const report = cli.executeOnFiles(argv[0]); + +// get the default formatter +const consoleFormatter = cli.getFormatter(); + +console.log('Lint finished'); + +// output to console +console.log(consoleFormatter(report.results)); + +// Output to sarif format +const otherFormatter = cli.getFormatter('@microsoft/eslint-formatter-sarif/sarif.js'); + +console.log('Saving sarif report..'); + +fs.writeFile('lint-results.sarif', otherFormatter(report.results), 'utf8', () => { + console.log('Sarif report saved'); + if (report.errorCount > 0) { + console.log('Errors found, exiting..'); + process.exit(1); + } else { + console.log('No errors found'); + process.exit(0); + } +});