UNPKG

@bentley/build-tools

Version:

Bentley build tools

112 lines (95 loc) 6.95 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ const fs = require("fs"); const path = require("path"); const { spawn } = require("child_process"); const { logBuildError, logBuildWarning, failBuild, throwAfterTimeout } = require("./utils"); const rushCommonDir = path.join(__dirname, "../../../../common/"); (async () => { const commonTempDir = path.join(rushCommonDir, "config/rush"); // Npm audit will occasionally take minutes to respond - we believe this is just the npm registry being terrible and slow. // We don't want this to slow down our builds though - we'd rather fail fast and try again later. So we'll just timeout after 30 seconds. let jsonOut = {}; try { console.time("Audit time"); jsonOut = await Promise.race([runPnpmAuditAsync(commonTempDir), throwAfterTimeout(180000, "Timed out contacting npm registry.")]); console.timeEnd("Audit time"); console.log(); } catch (error) { // We want to stop failing the build on transient failures and instead fail only on high/critical vulnerabilities. logBuildWarning(error); process.exit(); } if (jsonOut.error) { console.error(jsonOut.error.summary); logBuildWarning("Rush audit failed. This may be caused by a problem with the npm audit server."); } // A list of temporary advisories excluded from the High and Critical list. // Warning this should only be used as a temporary measure to avoid build failures // for development dependencies only. // All security issues should be addressed asap. const excludedAdvisories = [ "GHSA-ww39-953v-wcq6", // https://github.com/advisories/GHSA-ww39-953v-wcq6 @bentley/react-scripts>@pmmmwh/react-refresh-webpack-plugin>webpack-dev-server>chokidar>glob-parent, webpack>watchpack>(optional)watchpack-chokidar2>chokidar>glob-parent "GHSA-33f9-j839-rf8h", // https://github.com/advisories/GHSA-33f9-j839-rf8h @bentley/extension-webpack-tools>react-dev-utils>immer, @bentley/react-scripts>react-dev-utils>immer "GHSA-c36v-fmgq-m8hx", // https://github.com/advisories/GHSA-c36v-fmgq-m8hx @bentley/extension-webpack-tools>react-dev-utils>immer, @bentley/react-scripts>react-dev-utils>immer "GHSA-whgm-jr23-g3j9", // https://github.com/advisories/GHSA-whgm-jr23-g3j9 @bentley/react-scripts>@pmmmwh/react-refresh-webpack-plugin>ansi-html, @bentley/react-scripts>webpack-dev-server>ansi-html "GHSA-x4jg-mjrx-434g", // https://github.com/advisories/GHSA-x4jg-mjrx-434g @bentley/react-scripts>webpack-dev-server>selfsigned>node-forge "GHSA-cfm4-qjh2-4765", // https://github.com/advisories/GHSA-cfm4-qjh2-4765 @bentley/react-scripts>webpack-dev-server>selfsigned>node-forge "GHSA-fwr7-v2mv-hh25", // https://github.com/advisories/GHSA-fwr7-v2mv-hh25 @bentley/react-scripts>fast-sass-loader>async, @bentley/react-scripts>webpack-dev-server>portfinder>async "GHSA-phwq-j96m-2c2q", // https://github.com/advisories/GHSA-phwq-j96m-2c2q @bentley/react-scripts>workbox-webpack-plugin>workbox-build>@surma/rollup-plugin-off-main-thread>ejs "GHSA-6h5x-7c5m-7cr7", // https://github.com/advisories/GHSA-6h5x-7c5m-7cr7 @bentley/react-scripts>webpack-dev-server>sockjs-client>eventsource "GHSA-rp65-9cf3-cjxr", // https://github.com/advisories/GHSA-rp65-9cf3-cjxr @bentley/react-scripts>@svgr/webpack>@svgr/plugin-svgo>svgo>css-select>nth-check "GHSA-g4rg-993r-mgx7", // https://github.com/advisories/GHSA-g4rg-993r-mgx7 @bentley/react-scripts>react-dev-utils>shell-quote "GHSA-4wf5-vphf-c2xc", // https://github.com/advisories/GHSA-4wf5-vphf-c2xc @bentley/react-scripts>terser-webpack-plugin>terser "GHSA-f8q6-p94x-37v3", // https://github.com/advisories/GHSA-f8q6-p94x-37v3 react-dev-utils>recursive-readdir>minimatch "GHSA-76p3-8jx3-jpfq", // https://github.com/advisories/GHSA-76p3-8jx3-jpfq @bentley/react-scripts>loader-utils "GHSA-3rfm-jhwj-7488", // https://github.com/advisories/GHSA-3rfm-jhwj-7488 @bentley/react-scripts>react-dev-utils>loader-utils "GHSA-hhq3-ff78-jv3g", // https://github.com/advisories/GHSA-hhq3-ff78-jv3g @bentley/react-scripts>react-dev-utils>loader-utils "GHSA-27h2-hvpr-p74q", // https://github.com/advisories/GHSA-27h2-hvpr-p74q @bentley/core-backend>azurite>jsonwebtoken "GHSA-9c47-m6qq-7p4h", // https://github.com/advisories/GHSA-9c47-m6qq-7p4h @bentley/backend-application-insights-client>webpack>loader-utils>json5, @bentley/geonames-extension>svg-sprite-loader>html-webpack-plugin>loader-utils>json5, @bentley/ecschema-editing>i18next-node-fs-backend>json5 ]; let shouldFailBuild = false; for (const action of jsonOut.actions) { for (const issue of action.resolves) { const advisory = jsonOut.advisories[issue.id]; // TODO: This path no longer resolves to a specific package in the repo. Need to figure out the best way to handle it const mpath = issue.path; // .replace("@rush-temp", "@bentley"); const severity = advisory.severity.toUpperCase(); const message = `${severity} Security Vulnerability: ${advisory.title} in ${advisory.module_name} (from ${mpath}). See ${advisory.url} for more info.`; // For now, we'll only treat CRITICAL and HIGH vulnerabilities as errors in CI builds. if (!excludedAdvisories.includes(advisory.github_advisory_id) && (severity === "HIGH" || severity === "CRITICAL")) { logBuildError(message); shouldFailBuild = true; } else if (excludedAdvisories.includes(advisory.github_advisory_id) || severity === "MODERATE") // Only warn on MODERATE severity items logBuildWarning(message); } } // For some reason yarn audit can return the json without the vulnerabilities if (undefined === jsonOut.metadata.vulnerabilities || shouldFailBuild) failBuild(); process.exit(); })(); function runPnpmAuditAsync(cwd) { return new Promise((resolve, reject) => { // pnpm audit requires a package.json file so we temporarily create one and // then delete it later fs.writeFileSync(path.join(rushCommonDir, "config/rush/package.json"), JSON.stringify("{}", null, 2)); console.log("Running audit"); const pnpmPath = path.join(rushCommonDir, "temp/pnpm-local/node_modules/.bin/pnpm"); const child = spawn(pnpmPath, ["audit", "--json"], { cwd, shell: true }); let stdout = ""; child.stdout.on('data', (data) => { stdout += data; }); child.on('error', (data) => { fs.unlinkSync(path.join(rushCommonDir, "config/rush/package.json")); reject(data) }); child.on('close', () => { fs.unlinkSync(path.join(rushCommonDir, "config/rush/package.json")); resolve(JSON.parse(stdout.trim())); }); }); }