1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-10-22 03:12:42 +02:00

Add validation to production build script (#15468)

Validation has been added to the build script when the "prod" target is
selected. We now ensure that all expected environment variables are
set, and that no extra environment variables are present (which might
indicate that the wrong configuration file is being used).

The `prod` target uses a new `.metamaskprodrc` configuration file. Each
required variable can be specified either via environment variable or
via this config file. CI will continue set these via environment
variable, but for local manual builds we can use the config file to
simplify the build process and ensure consistency.

A new "dist" target has been added to preserve the ability to build a
"production-like" build without this validation.

The config validation is invoked early in the script, in the CLI
argument parsing step, so that it would fail more quickly. Otherwise
we'd have to wait a few minutes longer for the validation to run.
This required some refactoring, moving functions to the utility module
and moving the config to a dedicated module.

Additionally, support has been added for all environment variables to
be set via the config file. Previously the values `PUBNUB_PUB_KEY`,
`PUBNUB_SUB_KEY`, `SENTRY_DSN`, and `SWAPS_USE_DEV_APIS` could only be
set via environment variable. Now, all of these variables can be set
either way.

Closes #15003
This commit is contained in:
Mark Stacey 2022-08-19 14:16:18 -04:00 committed by GitHub
parent f26d2db338
commit 48c02ef641
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 311 additions and 177 deletions

View File

@ -246,9 +246,25 @@ jobs:
- checkout
- attach_workspace:
at: .
- run:
name: build:dist
command: yarn dist
- when:
condition:
not:
matches:
pattern: /^master$/
value: << pipeline.git.branch >>
steps:
- run:
name: build:dist
command: yarn build dist
- when:
condition:
matches:
pattern: /^master$/
value: << pipeline.git.branch >>
steps:
- run:
name: build:prod
command: yarn build prod
- run:
name: build:debug
command: find dist/ -type f -exec md5sum {} \; | sort -k 2
@ -266,7 +282,7 @@ jobs:
at: .
- run:
name: build:dist
command: yarn build --build-type beta prod
command: yarn build --build-type beta dist
- run:
name: build:debug
command: find dist/ -type f -exec md5sum {} \; | sort -k 2
@ -290,7 +306,7 @@ jobs:
at: .
- run:
name: build:dist
command: yarn build --build-type flask prod
command: yarn build --build-type flask dist
- run:
name: build:debug
command: find dist/ -type f -exec md5sum {} \; | sort -k 2

2
.gitignore vendored
View File

@ -47,7 +47,9 @@ notes.txt
.nyc_output
# MetaMask configuration
.metamaskrc
.metamaskprodrc
# TypeScript
tsout/

View File

@ -5,6 +5,8 @@ SEGMENT_WRITE_KEY=
ONBOARDING_V2=
SWAPS_USE_DEV_APIS=
COLLECTIBLES_V1=
PUBNUB_PUB_KEY=
PUBNUB_SUB_KEY=
; Set this to '1' to enable support for Sign-In with Ethereum [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361)
SIWE_V1=

101
development/build/config.js Normal file
View File

@ -0,0 +1,101 @@
const path = require('path');
const { readFile } = require('fs/promises');
const ini = require('ini');
const { BuildType } = require('../lib/build-type');
/**
* Get configuration for non-production builds.
*
* @returns {object} The production configuration.
*/
async function getConfig() {
const configPath = path.resolve(__dirname, '..', '..', '.metamaskrc');
let configContents = '';
try {
configContents = await readFile(configPath, {
encoding: 'utf8',
});
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
}
return {
COLLECTIBLES_V1: process.env.COLLECTIBLES_V1,
INFURA_PROJECT_ID: process.env.INFURA_PROJECT_ID,
ONBOARDING_V2: process.env.ONBOARDING_V2,
PHISHING_WARNING_PAGE_URL: process.env.PHISHING_WARNING_PAGE_URL,
PUBNUB_PUB_KEY: process.env.PUBNUB_PUB_KEY,
PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY,
SEGMENT_HOST: process.env.SEGMENT_HOST,
SEGMENT_WRITE_KEY: process.env.SEGMENT_WRITE_KEY,
SENTRY_DSN_DEV:
process.env.SENTRY_DSN_DEV ??
'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496',
SIWE_V1: process.env.SIWE_V1,
SWAPS_USE_DEV_APIS: process.env.SWAPS_USE_DEV_APIS,
...ini.parse(configContents),
};
}
/**
* Get configuration for production builds and perform validation.
*
* This function validates that all required variables are present, and that
* the production configuration file doesn't include any extraneous entries.
*
* @param {BuildType} buildType - The current build type (e.g. "main", "flask",
* etc.).
* @returns {object} The production configuration.
*/
async function getProductionConfig(buildType) {
const prodConfigPath = path.resolve(__dirname, '..', '..', '.metamaskprodrc');
let prodConfigContents = '';
try {
prodConfigContents = await readFile(prodConfigPath, {
encoding: 'utf8',
});
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
}
const prodConfig = {
INFURA_BETA_PROJECT_ID: process.env.INFURA_BETA_PROJECT_ID,
INFURA_FLASK_PROJECT_ID: process.env.INFURA_FLASK_PROJECT_ID,
INFURA_PROD_PROJECT_ID: process.env.INFURA_PROD_PROJECT_ID,
PUBNUB_PUB_KEY: process.env.PUBNUB_PUB_KEY,
PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY,
SEGMENT_BETA_WRITE_KEY: process.env.SEGMENT_BETA_WRITE_KEY,
SEGMENT_FLASK_WRITE_KEY: process.env.SEGMENT_FLASK_WRITE_KEY,
SEGMENT_PROD_WRITE_KEY: process.env.SEGMENT_PROD_WRITE_KEY,
SENTRY_DSN: process.env.SENTRY_DSN,
...ini.parse(prodConfigContents),
};
const requiredEnvironmentVariables = {
all: ['PUBNUB_PUB_KEY', 'PUBNUB_SUB_KEY', 'SENTRY_DSN'],
[BuildType.beta]: ['INFURA_BETA_PROJECT_ID', 'SEGMENT_BETA_WRITE_KEY'],
[BuildType.flask]: ['INFURA_FLASK_PROJECT_ID', 'SEGMENT_FLASK_WRITE_KEY'],
[BuildType.main]: ['INFURA_PROD_PROJECT_ID', 'SEGMENT_PROD_WRITE_KEY'],
};
for (const required of [
...requiredEnvironmentVariables.all,
...requiredEnvironmentVariables[buildType],
]) {
if (!prodConfig[required]) {
throw new Error(`Missing '${required}' environment variable`);
}
}
const allValid = Object.values(requiredEnvironmentVariables).flat();
for (const environmentVariable of Object.keys(prodConfig)) {
if (!allValid.includes(environmentVariable)) {
throw new Error(`Invalid environment variable: '${environmentVariable}'`);
}
}
return prodConfig;
}
module.exports = { getConfig, getProductionConfig };

View File

@ -1,27 +1,51 @@
/**
* The build target. This descrbes the overall purpose of the build.
*
* These constants also act as the high-level tasks for the build system (i.e.
* the usual tasks invoked directly via the CLI rather than internally).
*/
const BUILD_TARGETS = {
DEVELOPMENT: 'dev',
PRODUCTION: 'prod',
E2E_TEST: 'test',
E2E_TEST_DEV: 'testDev',
DEV: 'dev',
DIST: 'dist',
PROD: 'prod',
TEST: 'test',
TEST_DEV: 'testDev',
};
/**
* The build environment. This describes the environment this build was produced in.
*/
const ENVIRONMENT = {
DEVELOPMENT: 'development',
PRODUCTION: 'production',
OTHER: 'other',
PULL_REQUEST: 'pull-request',
RELEASE_CANDIDATE: 'release-candidate',
STAGING: 'staging',
TESTING: 'testing',
};
const TASKS = {
...BUILD_TARGETS,
CLEAN: 'clean',
DEV: 'dev',
LINT_SCSS: 'lint-scss',
MANIFEST_DEV: 'manifest:dev',
MANIFEST_PROD: 'manifest:prod',
MANIFEST_TEST: 'manifest:test',
MANIFEST_TEST_DEV: 'manifest:testDev',
PROD: 'prod',
RELOAD: 'reload',
SCRIPTS_PROD: 'scripts:prod',
SCRIPTS_CORE_DEV_STANDARD_ENTRY_POINTS:
'scripts:core:dev:standardEntryPoints',
SCRIPTS_CORE_DEV_CONTENTSCRIPT: 'scripts:core:dev:contentscript',
SCRIPTS_CORE_DEV_DISABLE_CONSOLE: 'scripts:core:dev:disable-console',
SCRIPTS_CORE_DEV_SENTRY: 'scripts:core:dev:sentry',
SCRIPTS_CORE_DEV_PHISHING_DETECT: 'scripts:core:dev:phishing-detect',
SCRIPTS_CORE_DIST_STANDARD_ENTRY_POINTS:
'scripts:core:dist:standardEntryPoints',
SCRIPTS_CORE_DIST_CONTENTSCRIPT: 'scripts:core:dist:contentscript',
SCRIPTS_CORE_DIST_DISABLE_CONSOLE: 'scripts:core:dist:disable-console',
SCRIPTS_CORE_DIST_SENTRY: 'scripts:core:dist:sentry',
SCRIPTS_CORE_DIST_PHISHING_DETECT: 'scripts:core:dist:phishing-detect',
SCRIPTS_CORE_PROD_STANDARD_ENTRY_POINTS:
'scripts:core:prod:standardEntryPoints',
SCRIPTS_CORE_PROD_CONTENTSCRIPT: 'scripts:core:prod:contentscript',
@ -42,14 +66,13 @@ const TASKS = {
SCRIPTS_CORE_TEST_DISABLE_CONSOLE: 'scripts:core:test:disable-console',
SCRIPTS_CORE_TEST_SENTRY: 'scripts:core:test:sentry',
SCRIPTS_CORE_TEST_PHISHING_DETECT: 'scripts:core:test:phishing-detect',
SCRIPTS_DIST: 'scripts:dist',
STATIC_DEV: 'static:dev',
STATIC_PROD: 'static:prod',
STYLES: 'styles',
STYLES_DEV: 'styles:dev',
STYLES_PROD: 'styles:prod',
TEST: 'test',
TEST_DEV: 'testDev',
ZIP: 'zip',
};
module.exports = { BUILD_TARGETS, TASKS };
module.exports = { BUILD_TARGETS, ENVIRONMENT, TASKS };

View File

@ -10,7 +10,7 @@ const { hideBin } = require('yargs/helpers');
const { sync: globby } = require('globby');
const { getVersion } = require('../lib/get-version');
const { BuildType } = require('../lib/build-type');
const { TASKS } = require('./constants');
const { TASKS, ENVIRONMENT } = require('./constants');
const {
createTask,
composeSeries,
@ -22,7 +22,9 @@ const createScriptTasks = require('./scripts');
const createStyleTasks = require('./styles');
const createStaticAssetTasks = require('./static');
const createEtcTasks = require('./etc');
const { getBrowserVersionMap } = require('./utils');
const { getBrowserVersionMap, getEnvironment } = require('./utils');
const { getConfig, getProductionConfig } = require('./config');
const { BUILD_TARGETS } = require('./constants');
// Packages required dynamically via browserify configuration in dependencies
// Required for LavaMoat policy generation
@ -50,9 +52,12 @@ require('eslint-plugin-react');
require('eslint-plugin-react-hooks');
require('eslint-plugin-jest');
defineAndRunBuildTasks();
defineAndRunBuildTasks().catch((error) => {
console.error(error.stack || error);
process.exitCode = 1;
});
function defineAndRunBuildTasks() {
async function defineAndRunBuildTasks() {
const {
applyLavaMoat,
buildType,
@ -63,7 +68,7 @@ function defineAndRunBuildTasks() {
shouldLintFenceFiles,
skipStats,
version,
} = parseArgv();
} = await parseArgv();
const browserPlatforms = ['firefox', 'chrome', 'brave', 'opera'];
@ -135,6 +140,17 @@ function defineAndRunBuildTasks() {
),
);
// build production-like distributable build
createTask(
TASKS.DIST,
composeSeries(
clean,
styleTasks.prod,
composeParallel(scriptTasks.dist, staticTasks.prod, manifestTasks.prod),
zip,
),
);
// build for prod release
createTask(
TASKS.PROD,
@ -147,7 +163,7 @@ function defineAndRunBuildTasks() {
);
// build just production scripts, for LavaMoat policy generation purposes
createTask(TASKS.SCRIPTS_PROD, scriptTasks.prod);
createTask(TASKS.SCRIPTS_DIST, scriptTasks.dist);
// build for CI testing
createTask(
@ -164,20 +180,22 @@ function defineAndRunBuildTasks() {
createTask(TASKS.styles, styleTasks.prod);
// Finally, start the build process by running the entry task.
runTask(entryTask, { skipStats });
await runTask(entryTask, { skipStats });
}
function parseArgv() {
async function parseArgv() {
const { argv } = yargs(hideBin(process.argv))
.usage('$0 <task> [options]', 'Build the MetaMask extension.', (_yargs) =>
_yargs
.positional('task', {
description: `The task to run. There are a number of main tasks, each of which calls other tasks internally. The main tasks are:
prod: Create an optimized build for a production environment.
dev: Create an unoptimized, live-reloading build for local development.
dist: Create an optimized production-like for a non-production environment.
prod: Create an optimized build for a production environment.
test: Create an optimized build for running e2e tests.
testDev: Create an unoptimized, live-reloading build for debugging e2e tests.`,
@ -254,6 +272,18 @@ testDev: Create an unoptimized, live-reloading build for debugging e2e tests.`,
const version = getVersion(buildType, buildVersion);
const highLevelTasks = Object.values(BUILD_TARGETS);
if (highLevelTasks.includes(task)) {
const environment = getEnvironment({ buildTarget: task });
if (environment === ENVIRONMENT.PRODUCTION) {
// Output ignored, this is only called to ensure config is validated
await getProductionConfig(buildType);
} else {
// Output ignored, this is only called to ensure config is validated
await getConfig();
}
}
return {
applyLavaMoat,
buildType,

View File

@ -24,45 +24,19 @@ const Sqrl = require('squirrelly');
const lavapack = require('@lavamoat/lavapack');
const lavamoatBrowserify = require('lavamoat-browserify');
const terser = require('terser');
const ini = require('ini');
const bifyModuleGroups = require('bify-module-groups');
const configPath = path.resolve(__dirname, '..', '..', '.metamaskrc');
let configContents = '';
try {
configContents = readFileSync(configPath, {
encoding: 'utf8',
});
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
}
const metamaskrc = {
INFURA_PROJECT_ID: process.env.INFURA_PROJECT_ID,
INFURA_BETA_PROJECT_ID: process.env.INFURA_BETA_PROJECT_ID,
INFURA_FLASK_PROJECT_ID: process.env.INFURA_FLASK_PROJECT_ID,
INFURA_PROD_PROJECT_ID: process.env.INFURA_PROD_PROJECT_ID,
ONBOARDING_V2: process.env.ONBOARDING_V2,
COLLECTIBLES_V1: process.env.COLLECTIBLES_V1,
PHISHING_WARNING_PAGE_URL: process.env.PHISHING_WARNING_PAGE_URL,
SEGMENT_HOST: process.env.SEGMENT_HOST,
SEGMENT_WRITE_KEY: process.env.SEGMENT_WRITE_KEY,
SEGMENT_BETA_WRITE_KEY: process.env.SEGMENT_BETA_WRITE_KEY,
SEGMENT_FLASK_WRITE_KEY: process.env.SEGMENT_FLASK_WRITE_KEY,
SEGMENT_PROD_WRITE_KEY: process.env.SEGMENT_PROD_WRITE_KEY,
SENTRY_DSN_DEV:
process.env.SENTRY_DSN_DEV ||
'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496',
SIWE_V1: process.env.SIWE_V1,
...ini.parse(configContents),
};
const { streamFlatMap } = require('../stream-flat-map');
const { BuildType } = require('../lib/build-type');
const { BUILD_TARGETS } = require('./constants');
const { logError } = require('./utils');
const { BUILD_TARGETS, ENVIRONMENT } = require('./constants');
const { getConfig, getProductionConfig } = require('./config');
const {
isDevBuild,
isTestBuild,
getEnvironment,
logError,
} = require('./utils');
const {
createTask,
@ -74,81 +48,28 @@ const {
createRemoveFencedCodeTransform,
} = require('./transforms/remove-fenced-code');
/**
* The build environment. This describes the environment this build was produced in.
*/
const ENVIRONMENT = {
DEVELOPMENT: 'development',
PRODUCTION: 'production',
OTHER: 'other',
PULL_REQUEST: 'pull-request',
RELEASE_CANDIDATE: 'release-candidate',
STAGING: 'staging',
TESTING: 'testing',
};
/**
* Returns whether the current build is a development build or not.
*
* @param {BUILD_TARGETS} buildTarget - The current build target.
* @returns Whether the current build is a development build.
*/
function isDevBuild(buildTarget) {
return (
buildTarget === BUILD_TARGETS.DEVELOPMENT ||
buildTarget === BUILD_TARGETS.E2E_TEST_DEV
);
}
/**
* Returns whether the current build is an e2e test build or not.
*
* @param {BUILD_TARGETS} buildTarget - The current build target.
* @returns Whether the current build is an e2e test build.
*/
function isTestBuild(buildTarget) {
return (
buildTarget === BUILD_TARGETS.E2E_TEST ||
buildTarget === BUILD_TARGETS.E2E_TEST_DEV
);
}
/**
* Get a value from the configuration, and confirm that it is set.
*
* @param {string} key - The configuration key to retrieve.
* @returns {string} The config entry requested.
* @throws {Error} Throws if the requested key is missing.
*/
function getConfigValue(key) {
const value = metamaskrc[key];
if (!value) {
throw new Error(`Missing config entry for '${key}'`);
}
return value;
}
/**
* Get the appropriate Infura project ID.
*
* @param {object} options - The Infura project ID options.
* @param {BuildType} options.buildType - The current build type.
* @param {object} options.config - The environment variable configuration.
* @param {ENVIRONMENT[keyof ENVIRONMENT]} options.environment - The build environment.
* @param {boolean} options.testing - Whether this is a test build or not.
* @returns {string} The Infura project ID.
*/
function getInfuraProjectId({ buildType, environment, testing }) {
function getInfuraProjectId({ buildType, config, environment, testing }) {
if (testing) {
return '00000000000000000000000000000000';
} else if (environment !== ENVIRONMENT.PRODUCTION) {
// Skip validation because this is unset on PRs from forks.
return metamaskrc.INFURA_PROJECT_ID;
return config.INFURA_PROJECT_ID;
} else if (buildType === BuildType.main) {
return getConfigValue('INFURA_PROD_PROJECT_ID');
return config.INFURA_PROD_PROJECT_ID;
} else if (buildType === BuildType.beta) {
return getConfigValue('INFURA_BETA_PROJECT_ID');
return config.INFURA_BETA_PROJECT_ID;
} else if (buildType === BuildType.flask) {
return getConfigValue('INFURA_FLASK_PROJECT_ID');
return config.INFURA_FLASK_PROJECT_ID;
}
throw new Error(`Invalid build type: '${buildType}'`);
}
@ -158,19 +79,20 @@ function getInfuraProjectId({ buildType, environment, testing }) {
*
* @param {object} options - The Segment write key options.
* @param {BuildType} options.buildType - The current build type.
* @param {object} options.config - The environment variable configuration.
* @param {keyof ENVIRONMENT} options.environment - The current build environment.
* @returns {string} The Segment write key.
*/
function getSegmentWriteKey({ buildType, environment }) {
function getSegmentWriteKey({ buildType, config, environment }) {
if (environment !== ENVIRONMENT.PRODUCTION) {
// Skip validation because this is unset on PRs from forks, and isn't necessary for development builds.
return metamaskrc.SEGMENT_WRITE_KEY;
return config.SEGMENT_WRITE_KEY;
} else if (buildType === BuildType.main) {
return getConfigValue('SEGMENT_PROD_WRITE_KEY');
return config.SEGMENT_PROD_WRITE_KEY;
} else if (buildType === BuildType.beta) {
return getConfigValue('SEGMENT_BETA_WRITE_KEY');
return config.SEGMENT_BETA_WRITE_KEY;
} else if (buildType === BuildType.flask) {
return getConfigValue('SEGMENT_FLASK_WRITE_KEY');
return config.SEGMENT_FLASK_WRITE_KEY;
}
throw new Error(`Invalid build type: '${buildType}'`);
}
@ -179,11 +101,12 @@ function getSegmentWriteKey({ buildType, environment }) {
* Get the URL for the phishing warning page, if it has been set.
*
* @param {object} options - The phishing warning page options.
* @param {object} options.config - The environment variable configuration.
* @param {boolean} options.testing - Whether this is a test build or not.
* @returns {string} The URL for the phishing warning page, or `undefined` if no URL is set.
*/
function getPhishingWarningPageUrl({ testing }) {
let phishingWarningPageUrl = metamaskrc.PHISHING_WARNING_PAGE_URL;
function getPhishingWarningPageUrl({ config, testing }) {
let phishingWarningPageUrl = config.PHISHING_WARNING_PAGE_URL;
if (!phishingWarningPageUrl) {
phishingWarningPageUrl = testing
@ -259,35 +182,35 @@ function createScriptTasks({
shouldLintFenceFiles,
version,
}) {
// internal tasks
const core = {
// high level tasks
return {
// dev tasks (live reload)
dev: createTasksForScriptBundles({
buildTarget: BUILD_TARGETS.DEVELOPMENT,
buildTarget: BUILD_TARGETS.DEV,
taskPrefix: 'scripts:core:dev',
}),
// production-like distributable build
dist: createTasksForScriptBundles({
buildTarget: BUILD_TARGETS.DIST,
taskPrefix: 'scripts:core:dist',
}),
// production
prod: createTasksForScriptBundles({
buildTarget: BUILD_TARGETS.PRODUCTION,
buildTarget: BUILD_TARGETS.PROD,
taskPrefix: 'scripts:core:prod',
}),
// built for CI tests
test: createTasksForScriptBundles({
buildTarget: BUILD_TARGETS.E2E_TEST,
buildTarget: BUILD_TARGETS.TEST,
taskPrefix: 'scripts:core:test',
}),
// built for CI test debugging
testDev: createTasksForScriptBundles({
buildTarget: BUILD_TARGETS.E2E_TEST_DEV,
buildTarget: BUILD_TARGETS.TEST_DEV,
taskPrefix: 'scripts:core:test-live',
}),
};
// high level tasks
const { dev, test, testDev, prod } = core;
return { dev, test, testDev, prod };
/**
* Define tasks for building the JavaScript modules used by the extension.
* This function returns a single task that builds JavaScript modules in
@ -595,7 +518,7 @@ function createFactoredBuild({
const reloadOnChange = isDevBuild(buildTarget);
const minify = !isDevBuild(buildTarget);
const envVars = getEnvironmentVariables({
const envVars = await getEnvironmentVariables({
buildTarget,
buildType,
version,
@ -823,11 +746,11 @@ function createNormalBundle({
const minify = Boolean(devMode) === false;
const envVars = {
...getEnvironmentVariables({
...(await getEnvironmentVariables({
buildTarget,
buildType,
version,
}),
})),
...extraEnvironmentVariables,
};
setupBundlerDefaults(buildConfiguration, {
@ -915,7 +838,7 @@ function setupBundlerDefaults(
});
// Ensure react-devtools is only included in dev builds
if (buildTarget !== BUILD_TARGETS.DEVELOPMENT) {
if (buildTarget !== BUILD_TARGETS.DEV) {
bundlerOpts.manualIgnore.push('react-devtools');
bundlerOpts.manualIgnore.push('remote-redux-devtools');
}
@ -1081,20 +1004,22 @@ async function createBundle(buildConfiguration, { reloadOnChange }) {
* @param {string} options.version - The current version of the extension.
* @returns {object} A map of environment variables to inject.
*/
function getEnvironmentVariables({ buildTarget, buildType, version }) {
async function getEnvironmentVariables({ buildTarget, buildType, version }) {
const environment = getEnvironment({ buildTarget });
if (environment === ENVIRONMENT.PRODUCTION && !process.env.SENTRY_DSN) {
throw new Error('Missing SENTRY_DSN environment variable');
}
const config =
environment === ENVIRONMENT.PRODUCTION
? await getProductionConfig(buildType)
: await getConfig();
const devMode = isDevBuild(buildTarget);
const testing = isTestBuild(buildTarget);
return {
COLLECTIBLES_V1: metamaskrc.COLLECTIBLES_V1 === '1',
CONF: devMode ? metamaskrc : {},
COLLECTIBLES_V1: config.COLLECTIBLES_V1 === '1',
CONF: devMode ? config : {},
IN_TEST: testing,
INFURA_PROJECT_ID: getInfuraProjectId({
buildType,
config,
environment,
testing,
}),
@ -1103,39 +1028,19 @@ function getEnvironmentVariables({ buildTarget, buildType, version }) {
METAMASK_VERSION: version,
METAMASK_BUILD_TYPE: buildType,
NODE_ENV: devMode ? ENVIRONMENT.DEVELOPMENT : ENVIRONMENT.PRODUCTION,
ONBOARDING_V2: metamaskrc.ONBOARDING_V2 === '1',
PHISHING_WARNING_PAGE_URL: getPhishingWarningPageUrl({ testing }),
PUBNUB_PUB_KEY: process.env.PUBNUB_PUB_KEY || '',
PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY || '',
SEGMENT_HOST: metamaskrc.SEGMENT_HOST,
SEGMENT_WRITE_KEY: getSegmentWriteKey({ buildType, environment }),
SENTRY_DSN: process.env.SENTRY_DSN,
SENTRY_DSN_DEV: metamaskrc.SENTRY_DSN_DEV,
SIWE_V1: metamaskrc.SIWE_V1 === '1',
SWAPS_USE_DEV_APIS: process.env.SWAPS_USE_DEV_APIS === '1',
ONBOARDING_V2: config.ONBOARDING_V2 === '1',
PHISHING_WARNING_PAGE_URL: getPhishingWarningPageUrl({ config, testing }),
PUBNUB_PUB_KEY: config.PUBNUB_PUB_KEY || '',
PUBNUB_SUB_KEY: config.PUBNUB_SUB_KEY || '',
SEGMENT_HOST: config.SEGMENT_HOST,
SEGMENT_WRITE_KEY: getSegmentWriteKey({ buildType, config, environment }),
SENTRY_DSN: config.SENTRY_DSN,
SENTRY_DSN_DEV: config.SENTRY_DSN_DEV,
SIWE_V1: config.SIWE_V1 === '1',
SWAPS_USE_DEV_APIS: config.SWAPS_USE_DEV_APIS === '1',
};
}
function getEnvironment({ buildTarget }) {
// get environment slug
if (isDevBuild(buildTarget)) {
return ENVIRONMENT.DEVELOPMENT;
} else if (isTestBuild(buildTarget)) {
return ENVIRONMENT.TESTING;
} else if (process.env.CIRCLE_BRANCH === 'master') {
return ENVIRONMENT.PRODUCTION;
} else if (
/^Version-v(\d+)[.](\d+)[.](\d+)/u.test(process.env.CIRCLE_BRANCH)
) {
return ENVIRONMENT.RELEASE_CANDIDATE;
} else if (process.env.CIRCLE_BRANCH === 'develop') {
return ENVIRONMENT.STAGING;
} else if (process.env.CIRCLE_PULL_REQUEST) {
return ENVIRONMENT.PULL_REQUEST;
}
return ENVIRONMENT.OTHER;
}
function renderHtmlFile({
htmlName,
groupSet,

View File

@ -1,5 +1,30 @@
const semver = require('semver');
const { BuildType } = require('../lib/build-type');
const { BUILD_TARGETS, ENVIRONMENT } = require('./constants');
/**
* Returns whether the current build is a development build or not.
*
* @param {BUILD_TARGETS} buildTarget - The current build target.
* @returns Whether the current build is a development build.
*/
function isDevBuild(buildTarget) {
return (
buildTarget === BUILD_TARGETS.DEV || buildTarget === BUILD_TARGETS.TEST_DEV
);
}
/**
* Returns whether the current build is an e2e test build or not.
*
* @param {BUILD_TARGETS} buildTarget - The current build target.
* @returns Whether the current build is an e2e test build.
*/
function isTestBuild(buildTarget) {
return (
buildTarget === BUILD_TARGETS.TEST || buildTarget === BUILD_TARGETS.TEST_DEV
);
}
/**
* Map the current version to a format that is compatible with each browser.
@ -51,6 +76,33 @@ function getBrowserVersionMap(platforms, version) {
}, {});
}
/**
* Get the environment of the current build.
*
* @param {object} options - Build options.
* @param {BUILD_TARGETS} options.buildTarget - The target of the current build.
* @returns {ENVIRONMENT} The current build environment.
*/
function getEnvironment({ buildTarget }) {
// get environment slug
if (buildTarget === BUILD_TARGETS.PROD) {
return ENVIRONMENT.PRODUCTION;
} else if (isDevBuild(buildTarget)) {
return ENVIRONMENT.DEVELOPMENT;
} else if (isTestBuild(buildTarget)) {
return ENVIRONMENT.TESTING;
} else if (
/^Version-v(\d+)[.](\d+)[.](\d+)/u.test(process.env.CIRCLE_BRANCH)
) {
return ENVIRONMENT.RELEASE_CANDIDATE;
} else if (process.env.CIRCLE_BRANCH === 'develop') {
return ENVIRONMENT.STAGING;
} else if (process.env.CIRCLE_PULL_REQUEST) {
return ENVIRONMENT.PULL_REQUEST;
}
return ENVIRONMENT.OTHER;
}
/**
* Log an error to the console.
*
@ -67,5 +119,8 @@ function logError(error) {
module.exports = {
getBrowserVersionMap,
getEnvironment,
isDevBuild,
isTestBuild,
logError,
};

View File

@ -12,7 +12,7 @@
"start": "yarn build:dev dev --apply-lavamoat=false",
"start:lavamoat": "yarn build:dev dev --apply-lavamoat=true",
"start:mv3": "ENABLE_MV3=true yarn build:dev dev --apply-lavamoat=false",
"dist": "yarn build prod",
"dist": "yarn build dist",
"build": "yarn lavamoat:build",
"build:dev": "node development/build/index.js",
"start:test": "SEGMENT_HOST='https://api.segment.io' SEGMENT_WRITE_KEY='FAKE' yarn build testDev",