Commit 4b42b71e authored by tom goriunov's avatar tom goriunov Committed by GitHub

ENVs changes and test script for validator (#1296)

* use SENTRY_CSP_REPORT_URI only in nextjs part of the app

* rename NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY to FAVICON_GENERATOR_API_KEY

* tests presets for envs validator

* simplify logs

* refactor getExternalJsonContent function

* tweak contribution guide

* break validator

* debug workflow

* fix copying assets folder

* fix CI
parent 0af703d5
...@@ -5,4 +5,4 @@ NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=xxx ...@@ -5,4 +5,4 @@ NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=xxx
NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID=UA-XXXXXX-X NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID=UA-XXXXXX-X
NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN=xxx NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN=xxx
NEXT_PUBLIC_AUTH0_CLIENT_ID=xxx NEXT_PUBLIC_AUTH0_CLIENT_ID=xxx
NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY=xxx FAVICON_GENERATOR_API_KEY=xxx
\ No newline at end of file \ No newline at end of file
...@@ -305,7 +305,7 @@ module.exports = { ...@@ -305,7 +305,7 @@ module.exports = {
}, },
}, },
{ {
files: [ '*.config.ts', 'playwright/**', 'deploy/tools/**', 'middleware.ts' ], files: [ '*.config.ts', 'playwright/**', 'deploy/tools/**', 'middleware.ts', 'nextjs/**' ],
rules: { rules: {
// for configs allow to consume env variables from process.env directly // for configs allow to consume env variables from process.env directly
'no-restricted-properties': [ 0 ], 'no-restricted-properties': [ 0 ],
......
...@@ -52,7 +52,7 @@ jobs: ...@@ -52,7 +52,7 @@ jobs:
run: yarn lint:tsc run: yarn lint:tsc
envs_validation: envs_validation:
name: ENV variables presets validation name: ENV variables validation
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [ code_quality ] needs: [ code_quality ]
steps: steps:
...@@ -80,13 +80,10 @@ jobs: ...@@ -80,13 +80,10 @@ jobs:
- name: Install script dependencies - name: Install script dependencies
run: cd ./deploy/tools/envs-validator && yarn --frozen-lockfile --ignore-optional run: cd ./deploy/tools/envs-validator && yarn --frozen-lockfile --ignore-optional
- name: Copy secrets file - name: Run validation tests
run: cp ./.env.example ./configs/envs/.env.secrets
- name: Run validation script
run: | run: |
set +e set +e
cd ./deploy/tools/envs-validator && yarn dev cd ./deploy/tools/envs-validator && yarn test
exitcode="$?" exitcode="$?"
echo "exitcode=$exitcode" >> $GITHUB_OUTPUT echo "exitcode=$exitcode" >> $GITHUB_OUTPUT
exit "$exitcode" exit "$exitcode"
......
...@@ -14,25 +14,10 @@ const instance = (() => { ...@@ -14,25 +14,10 @@ const instance = (() => {
})(); })();
const environment = getEnvValue('NEXT_PUBLIC_APP_ENV') || 'production'; const environment = getEnvValue('NEXT_PUBLIC_APP_ENV') || 'production';
const release = getEnvValue('NEXT_PUBLIC_GIT_TAG'); const release = getEnvValue('NEXT_PUBLIC_GIT_TAG');
const cspReportUrl = (() => {
try {
const url = new URL(getEnvValue('SENTRY_CSP_REPORT_URI') || '');
// https://docs.sentry.io/product/security-policy-reporting/#additional-configuration
url.searchParams.set('sentry_environment', environment);
release && url.searchParams.set('sentry_release', release);
return url.toString();
} catch (error) {
return;
}
})();
const title = 'Sentry error monitoring'; const title = 'Sentry error monitoring';
const config: Feature<{ const config: Feature<{
dsn: string; dsn: string;
cspReportUrl: string | undefined;
instance: string; instance: string;
release: string | undefined; release: string | undefined;
environment: string; environment: string;
...@@ -42,7 +27,6 @@ const config: Feature<{ ...@@ -42,7 +27,6 @@ const config: Feature<{
title, title,
isEnabled: true, isEnabled: true,
dsn, dsn,
cspReportUrl,
instance, instance,
release, release,
environment, environment,
......
#!/bin/bash #!/bin/bash
master_url="${NEXT_PUBLIC_FAVICON_MASTER_URL:-$NEXT_PUBLIC_NETWORK_ICON}" master_url="${FAVICON_MASTER_URL:-$NEXT_PUBLIC_NETWORK_ICON}"
export MASTER_URL="$master_url" export MASTER_URL="$master_url"
cd ./deploy/tools/favicon-generator cd ./deploy/tools/favicon-generator
......
...@@ -2,4 +2,5 @@ ...@@ -2,4 +2,5 @@
/public /public
.env .env
.env.registry .env.registry
.env.secrets
index.js index.js
\ No newline at end of file
...@@ -3,12 +3,15 @@ import fs from 'fs'; ...@@ -3,12 +3,15 @@ import fs from 'fs';
import path from 'path'; import path from 'path';
import type { ValidationError } from 'yup'; import type { ValidationError } from 'yup';
import { buildExternalAssetFilePath } from '../../../configs/app/utils';
import schema from './schema'; import schema from './schema';
const silent = process.argv.includes('--silent');
run(); run();
async function run() { async function run() {
console.log(); !silent && console.log();
try { try {
const appEnvs = Object.entries(process.env) const appEnvs = Object.entries(process.env)
.filter(([ key ]) => key.startsWith('NEXT_PUBLIC_')) .filter(([ key ]) => key.startsWith('NEXT_PUBLIC_'))
...@@ -26,25 +29,22 @@ async function run() { ...@@ -26,25 +29,22 @@ async function run() {
} }
async function validateEnvs(appEnvs: Record<string, string>) { async function validateEnvs(appEnvs: Record<string, string>) {
console.log(`🌀 Validating ENV variables values...`); !silent && console.log(`🌀 Validating ENV variables values...`);
try { try {
// replace ENVs with external JSON files content // replace ENVs with external JSON files content
appEnvs.NEXT_PUBLIC_FEATURED_NETWORKS = await getExternalJsonContent( const envsWithJsonConfig = [
'./public/assets/featured_networks.json', 'NEXT_PUBLIC_FEATURED_NETWORKS',
appEnvs.NEXT_PUBLIC_FEATURED_NETWORKS, 'NEXT_PUBLIC_MARKETPLACE_CONFIG_URL',
) || '[]'; 'NEXT_PUBLIC_FOOTER_LINKS',
appEnvs.NEXT_PUBLIC_MARKETPLACE_CONFIG_URL = await getExternalJsonContent( ];
'./public/assets/marketplace_config.json',
appEnvs.NEXT_PUBLIC_MARKETPLACE_CONFIG_URL, for await (const envName of envsWithJsonConfig) {
) || '[]'; appEnvs[envName] = await(appEnvs[envName] ? getExternalJsonContent(envName) : Promise.resolve()) || '[]';
appEnvs.NEXT_PUBLIC_FOOTER_LINKS = await getExternalJsonContent( }
'./public/assets/footer_links.json',
appEnvs.NEXT_PUBLIC_FOOTER_LINKS,
) || '[]';
await schema.validate(appEnvs, { stripUnknown: false, abortEarly: false }); await schema.validate(appEnvs, { stripUnknown: false, abortEarly: false });
console.log('👍 All good!'); !silent && console.log('👍 All good!');
} catch (_error) { } catch (_error) {
if (typeof _error === 'object' && _error !== null && 'errors' in _error) { if (typeof _error === 'object' && _error !== null && 'errors' in _error) {
console.log('🚨 ENVs validation failed with the following errors:'); console.log('🚨 ENVs validation failed with the following errors:');
...@@ -59,15 +59,12 @@ async function validateEnvs(appEnvs: Record<string, string>) { ...@@ -59,15 +59,12 @@ async function validateEnvs(appEnvs: Record<string, string>) {
throw _error; throw _error;
} }
console.log(); !silent && console.log();
} }
async function getExternalJsonContent(fileName: string, envValue: string): Promise<string | void> { async function getExternalJsonContent(envName: string): Promise<string | void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!envValue) { const fileName = `./public${ buildExternalAssetFilePath(envName, '.json') }`;
resolve();
return;
}
fs.readFile(path.resolve(__dirname, fileName), 'utf8', (err, data) => { fs.readFile(path.resolve(__dirname, fileName), 'utf8', (err, data) => {
if (err) { if (err) {
...@@ -83,7 +80,7 @@ async function getExternalJsonContent(fileName: string, envValue: string): Promi ...@@ -83,7 +80,7 @@ async function getExternalJsonContent(fileName: string, envValue: string): Promi
async function checkPlaceholdersCongruity(envsMap: Record<string, string>) { async function checkPlaceholdersCongruity(envsMap: Record<string, string>) {
try { try {
console.log(`🌀 Checking environment variables and their placeholders congruity...`); !silent && console.log(`🌀 Checking environment variables and their placeholders congruity...`);
const runTimeEnvs = await getEnvsPlaceholders(path.resolve(__dirname, '.env.registry')); const runTimeEnvs = await getEnvsPlaceholders(path.resolve(__dirname, '.env.registry'));
const buildTimeEnvs = await getEnvsPlaceholders(path.resolve(__dirname, '.env')); const buildTimeEnvs = await getEnvsPlaceholders(path.resolve(__dirname, '.env'));
...@@ -108,7 +105,7 @@ async function checkPlaceholdersCongruity(envsMap: Record<string, string>) { ...@@ -108,7 +105,7 @@ async function checkPlaceholdersCongruity(envsMap: Record<string, string>) {
throw new Error(); throw new Error();
} }
console.log('👍 All good!\n'); !silent && console.log('👍 All good!\n');
} catch (error) { } catch (error) {
console.log('🚨 Congruity check failed.\n'); console.log('🚨 Congruity check failed.\n');
throw error; throw error;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
"scripts": { "scripts": {
"build": "yarn webpack-cli -c ./webpack.config.js", "build": "yarn webpack-cli -c ./webpack.config.js",
"validate": "node ./index.js", "validate": "node ./index.js",
"dev": "./dev.sh" "test": "./test.sh"
}, },
"dependencies": { "dependencies": {
"ts-loader": "^9.4.4", "ts-loader": "^9.4.4",
......
...@@ -438,7 +438,6 @@ const schema = yup ...@@ -438,7 +438,6 @@ const schema = yup
NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY: yup.string(), NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY: yup.string(),
NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: yup.string(), NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: yup.string(),
NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN: yup.string(), NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN: yup.string(),
NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY: yup.string(),
// Misc // Misc
NEXT_PUBLIC_USE_NEXT_JS_PROXY: yup.boolean(), NEXT_PUBLIC_USE_NEXT_JS_PROXY: yup.boolean(),
......
#!/bin/bash #!/bin/bash
secrets_file=".env.secrets"
test_folder="./test"
common_file="${test_folder}/.env.common"
# Generate ENV registry file
export NEXT_PUBLIC_GIT_COMMIT_SHA=$(git rev-parse --short HEAD) export NEXT_PUBLIC_GIT_COMMIT_SHA=$(git rev-parse --short HEAD)
export NEXT_PUBLIC_GIT_TAG=$(git describe --tags --abbrev=0) export NEXT_PUBLIC_GIT_TAG=$(git describe --tags --abbrev=0)
../../scripts/collect_envs.sh ../../../docs/ENVS.md ../../scripts/collect_envs.sh ../../../docs/ENVS.md
cp ../../../.env.example ${secrets_file}
yarn build # Copy test assets
mkdir -p "./public/assets"
cp -r ${test_folder}/assets ./public/
PRESETS=( # Build validator script
"main" yarn build
"main.L2"
)
validate_preset() { validate_file() {
local preset="$1" local test_file="$1"
secrets_file="../../../configs/envs/.env.secrets"
config_file="../../../configs/envs/.env.${preset}"
echo echo
echo "------------------------------------------------" echo "🧿 Validating file '$test_file'..."
echo "🧿 Validating preset '$preset'..."
dotenv \ dotenv \
-e $config_file \ -e $test_file \
-- bash -c '../../scripts/download_assets.sh ./public/assets' -e $common_file \
dotenv \
-e $config_file \
-e $secrets_file \ -e $secrets_file \
yarn validate yarn run validate -- --silent
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo "✅ Preset '$preset' is valid." echo "👍 All good!"
echo "------------------------------------------------"
echo
return 0 return 0
else else
echo "🛑 Preset '$preset' is invalid. Please fix it and run script again." echo "🛑 The file is invalid. Please fix errors and run script again."
echo "------------------------------------------------"
echo echo
return 1 return 1
fi fi
} }
test_files=($(find "$test_folder" -maxdepth 1 -type f | grep -vE '\/\.env\.common$'))
for preset in "${PRESETS[@]}"; do for file in "${test_files[@]}"; do
validate_preset "$preset" validate_file "$file"
if [ $? -eq 1 ]; then if [ $? -eq 1 ]; then
exit 1 exit 1
fi fi
......
NEXT_PUBLIC_AD_BANNER_PROVIDER=adbutler
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP={'id':'123456','width':'728','height':'90'}
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE={'id':'654321','width':'300','height':'100'}
\ No newline at end of file
NEXT_PUBLIC_AD_TEXT_PROVIDER=coinzilla
NEXT_PUBLIC_AD_BANNER_PROVIDER=slise
NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://example.com
NEXT_PUBLIC_API_BASE_PATH=/
NEXT_PUBLIC_API_SPEC_URL=https://example.com
NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws
NEXT_PUBLIC_APP_ENV=development
NEXT_PUBLIC_APP_PORT=3000
NEXT_PUBLIC_APP_PROTOCOL=http
NEXT_PUBLIC_BRIDGED_TOKENS_CHAINS=[{'id':'1','title':'Ethereum','short_title':'ETH','base_url':'https://example.com'}]
NEXT_PUBLIC_BRIDGED_TOKENS_BRIDGES=[{'type':'omni','title':'OmniBridge','short_title':'OMNI'}]
NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://example.com
NEXT_PUBLIC_FEATURED_NETWORKS=https://example.com
NEXT_PUBLIC_FOOTER_LINKS=https://example.com
NEXT_PUBLIC_GRAPHIQL_TRANSACTION=0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
NEXT_PUBLIC_HIDE_INDEXING_ALERT=false
NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs']
NEXT_PUBLIC_HOMEPAGE_PLATE_TEXT_COLOR='#fff'
NEXT_PUBLIC_HOMEPAGE_PLATE_BACKGROUND='rgb(255, 145, 0)'
NEXT_PUBLIC_HOMEPAGE_SHOW_GAS_TRACKER=true
NEXT_PUBLIC_HOMEPAGE_SHOW_AVG_BLOCK_TIME=true
NEXT_PUBLIC_IS_TESTNET=true
NEXT_PUBLIC_MARKETPLACE_CONFIG_URL=https://example.com
NEXT_PUBLIC_MARKETPLACE_SUBMIT_FORM=https://example.com
NEXT_PUBLIC_MAINTENANCE_ALERT_MESSAGE='<a href="#">Hello</a>'
NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18
NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Ether
NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=ETH
NEXT_PUBLIC_NETWORK_EXPLORERS=[{'title':'Explorer','baseUrl':'https://example.com/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]
NEXT_PUBLIC_NETWORK_GOVERNANCE_TOKEN_SYMBOL=gETH
NEXT_PUBLIC_NETWORK_ICON=https://example.com/icon.png
NEXT_PUBLIC_NETWORK_ICON_DARK=https://example.com/icon.png
NEXT_PUBLIC_NETWORK_LOGO=https://example.com/logo.png
NEXT_PUBLIC_NETWORK_LOGO_DARK=https://example.com/logo.png
NEXT_PUBLIC_NETWORK_RPC_URL=https://example.com
NEXT_PUBLIC_NETWORK_SHORT_NAME=Test
NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation
NEXT_PUBLIC_OG_DESCRIPTION='Hello world!'
NEXT_PUBLIC_OG_IMAGE_URL=https://example.com/image.png
NEXT_PUBLIC_OTHER_LINKS=[{'url':'https://blockscout.com','text':'Blockscout'}]
NEXT_PUBLIC_PROMOTE_BLOCKSCOUT_IN_TITLE=true
NEXT_PUBLIC_STATS_API_HOST=https://example.com
NEXT_PUBLIC_USE_NEXT_JS_PROXY=false
NEXT_PUBLIC_VIEWS_ADDRESS_IDENTICON_TYPE=gradient_avatar
NEXT_PUBLIC_VIEWS_ADDRESS_HIDDEN_VIEWS=['top_accounts']
NEXT_PUBLIC_VIEWS_BLOCK_HIDDEN_FIELDS=['burnt_fees','total_reward']
NEXT_PUBLIC_VIEWS_NFT_MARKETPLACES=[{'name':'NFT Marketplace','collection_url':'https://example.com/{hash}','instance_url':'https://example.com/{hash}/{id}','logo_url':'https://example.com/logo.png'}]
NEXT_PUBLIC_VIEWS_TX_ADDITIONAL_FIELDS=['fee_per_gas']
NEXT_PUBLIC_VIEWS_TX_HIDDEN_FIELDS=['value','fee_currency','gas_price','tx_fee','gas_fees','burnt_fees']
NEXT_PUBLIC_VISUALIZE_API_HOST=https://example.com
NEXT_PUBLIC_WEB3_DISABLE_ADD_TOKEN_TO_WALLET=false
NEXT_PUBLIC_WEB3_WALLETS=['coinbase','metamask','token_pocket']
\ No newline at end of file
NEXT_PUBLIC_HAS_BEACON_CHAIN=true
NEXT_PUBLIC_BEACON_CHAIN_CURRENCY_SYMBOL=aETH
\ No newline at end of file
NEXT_PUBLIC_API_HOST=blockscout.com
NEXT_PUBLIC_APP_HOST=localhost
NEXT_PUBLIC_AUTH_URL=https://example.com
NEXT_PUBLIC_IS_ACCOUNT_SUPPORTED=true
NEXT_PUBLIC_LOGOUT_URL=https://example.com
NEXT_PUBLIC_NETWORK_ID=1
NEXT_PUBLIC_NETWORK_NAME=Testnet
NEXT_PUBLIC_IS_L2_NETWORK=true
NEXT_PUBLIC_L1_BASE_URL=https://example.com
NEXT_PUBLIC_L2_WITHDRAWAL_URL=https://example.com
\ No newline at end of file
[
{
"title": "Ethereum",
"url": "https://eth.blockscout.com/",
"group": "Mainnets",
"icon": "https://example.com/logo.svg"
},
{
"title": "Goerli",
"url": "https://eth-goerli.blockscout.com/",
"group": "Testnets",
"isActive": true,
"icon": "https://example.com/logo.svg",
"invertIconInDarkMode": true
},
{
"title": "POA Sokol",
"url": "https://blockscout.com/poa/sokol",
"group": "Other",
"icon": "https://example.com/logo.svg"
}
]
\ No newline at end of file
[
{
"title": "Foo",
"links": [
{
"text": "Home",
"url": "https://example.com"
},
{
"text": "Brand",
"url": "https://example.com"
}
]
},
{
"title": "Developers",
"links": [
{
"text": "Develop",
"url": "https://example.com"
},
{
"text": "Grants",
"url": "https://example.com"
}
]
}
]
\ No newline at end of file
[
{
"author": "Hop",
"id": "hop-exchange",
"title": "Hop",
"logo": "https://example.com/logo.svg",
"categories": ["Bridge"],
"shortDescription": "Hop is a scalable rollup-to-rollup general token bridge.",
"site": "https://example.com",
"description": "Hop is a scalable rollup-to-rollup general token bridge.",
"external": true,
"url": "https://example.com"
},
{
"author": "Blockscout",
"id": "token-approval-tracker",
"title": "Token Approval Tracker",
"logo": "https://example.com/logo.svg",
"categories": ["Infra & Dev tooling"],
"shortDescription": "Token Approval Tracker shows all approvals for any ERC20-compliant tokens and NFTs and lets to revoke them or adjust the approved amount.",
"site": "https://example.com",
"description": "Token Approval Tracker shows all approvals for any ERC20-compliant tokens and NFTs and lets to revoke them or adjust the approved amount.",
"url": "https://example.com"
}
]
...@@ -8,7 +8,13 @@ ...@@ -8,7 +8,13 @@
"nextjs-routes": ["./nextjs/nextjs-routes.d.ts"], "nextjs-routes": ["./nextjs/nextjs-routes.d.ts"],
} }
}, },
"include": [ "../../../types/**/*.ts", "../../../global.d.ts", "./index.ts", "./schema.ts" ], "include": [
"../../../types/**/*.ts",
"../../../configs/app/**/*.ts",
"../../../global.d.ts",
"./index.ts",
"./schema.ts"
],
"tsc-alias": { "tsc-alias": {
"verbose": true, "verbose": true,
"resolveFullPaths": true, "resolveFullPaths": true,
......
...@@ -8,17 +8,17 @@ if [ -z "$MASTER_URL" ]; then ...@@ -8,17 +8,17 @@ if [ -z "$MASTER_URL" ]; then
exit 1 exit 1
fi fi
# Check if NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY is provided # Check if FAVICON_GENERATOR_API_KEY is provided
if [ -z "$NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY" ]; then if [ -z "$FAVICON_GENERATOR_API_KEY" ]; then
echo "🛑 Error: NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY variable is not provided." echo "🛑 Error: FAVICON_GENERATOR_API_KEY variable is not provided."
exit 1 exit 1
fi fi
# Mask the NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY to display only the first 8 characters # Mask the FAVICON_GENERATOR_API_KEY to display only the first 8 characters
API_KEY_MASKED="${NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY:0:8}***" API_KEY_MASKED="${FAVICON_GENERATOR_API_KEY:0:8}***"
echo "🆗 The following variables are provided:" echo "🆗 The following variables are provided:"
echo " MASTER_URL: $MASTER_URL" echo " MASTER_URL: $MASTER_URL"
echo " NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY: $API_KEY_MASKED" echo " FAVICON_GENERATOR_API_KEY: $API_KEY_MASKED"
echo echo
# RealFaviconGenerator API endpoint URL # RealFaviconGenerator API endpoint URL
...@@ -34,7 +34,7 @@ CONFIG_TEMPLATE_FILE="config.template.json" ...@@ -34,7 +34,7 @@ CONFIG_TEMPLATE_FILE="config.template.json"
CONFIG_FILE="config.json" CONFIG_FILE="config.json"
# Replace <api_key> and <master_url> placeholders in the JSON template file # Replace <api_key> and <master_url> placeholders in the JSON template file
API_KEY_VALUE="$NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY" API_KEY_VALUE="$FAVICON_GENERATOR_API_KEY"
sed -e "s|<api_key>|$API_KEY_VALUE|" -e "s|<master_url>|$MASTER_URL|" "$CONFIG_TEMPLATE_FILE" > "$CONFIG_FILE" sed -e "s|<api_key>|$API_KEY_VALUE|" -e "s|<master_url>|$MASTER_URL|" "$CONFIG_TEMPLATE_FILE" > "$CONFIG_FILE"
# Make the API POST request with JSON data from the config file # Make the API POST request with JSON data from the config file
......
...@@ -203,4 +203,4 @@ frontend: ...@@ -203,4 +203,4 @@ frontend:
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID
NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY
NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID
NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY FAVICON_GENERATOR_API_KEY: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY
...@@ -167,4 +167,4 @@ frontend: ...@@ -167,4 +167,4 @@ frontend:
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID
NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY
NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ref+vault://deployment-values/blockscout/dev/front-main?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID
NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY FAVICON_GENERATOR_API_KEY: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY
...@@ -144,7 +144,7 @@ frontend: ...@@ -144,7 +144,7 @@ frontend:
_default: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY _default: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY
NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID:
_default: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID _default: ref+vault://deployment-values/blockscout/dev/review-l2?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID
NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY: FAVICON_GENERATOR_API_KEY:
_default: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY _default: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY
NEXT_PUBLIC_OG_IMAGE_URL: NEXT_PUBLIC_OG_IMAGE_URL:
_default: https://github.com/blockscout/frontend-configs/blob/main/configs/og-images/base-goerli.png?raw=true _default: https://github.com/blockscout/frontend-configs/blob/main/configs/og-images/base-goerli.png?raw=true
...@@ -129,7 +129,7 @@ frontend: ...@@ -129,7 +129,7 @@ frontend:
_default: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY _default: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY
NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID:
_default: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID _default: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID
NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY: FAVICON_GENERATOR_API_KEY:
_default: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY _default: ref+vault://deployment-values/blockscout/common?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY
NEXT_PUBLIC_WEB3_WALLETS: NEXT_PUBLIC_WEB3_WALLETS:
_default: "['token_pocket','coinbase','metamask']" _default: "['token_pocket','coinbase','metamask']"
......
...@@ -81,13 +81,17 @@ These are the steps that you have to follow to make everything work: ...@@ -81,13 +81,17 @@ These are the steps that you have to follow to make everything work:
- `deploy/values/main/values.yaml` - main development environment - `deploy/values/main/values.yaml` - main development environment
- `deploy/values/review-l2/values.yaml.gotmpl` - review development environment for L2 networks - `deploy/values/review-l2/values.yaml.gotmpl` - review development environment for L2 networks
- `deploy/values/l2-optimism-goerli/values.yaml` - main development environment - `deploy/values/l2-optimism-goerli/values.yaml` - main development environment
5. Add validation schema for the new variable into the file `deploy/tools/envs-validator/schema.ts`; verify that any or all updated config presets from "Step 3" are valid by doing the following steps: 5. If your variable is meant to receive a link to some external resource (image or JSON-config file), extend the array `ASSETS_ENVS` in `deploy/scripts/download_assets.sh` with your variable name
6. Add validation schema for the new variable into the file `deploy/tools/envs-validator/schema.ts`
7. Check if modified validation schema is valid by doing the following steps:
- change your current directory to `deploy/tools/envs-validator` - change your current directory to `deploy/tools/envs-validator`
- install deps with `yarn` command - install deps with `yarn` command
- change `PRESETS` array in `dev.sh` script file accordingly - add your variable into `./test/.env.base` test preset or create a new test preset if needed
- run `yarn dev` command and see the validation result - if your variable contains a link to the external JSON config file:
- *Please* do not commit your changes in the `dev.sh` file since it is also used in the CI workflow - add example of file content into `./test/assets` directory; the file name should be constructed by stripping away prefix `NEXT_PUBLIC_` and postfix `_URL` if any, and converting the remaining string to lowercase (for example, `NEXT_PUBLIC_MARKETPLACE_CONFIG_URL` will become `marketplace_config.json`)
6. Don't forget to mention in the PR notes that new ENV variable was added - in the main script `index.ts` extend array `envsWithJsonConfig` with your variable name
- run `yarn test` command to see the validation result
8. Don't forget to mention in the PR notes that new ENV variable was added
&nbsp; &nbsp;
......
...@@ -148,8 +148,8 @@ By default, the app has generic favicon. You can override this behavior by provi ...@@ -148,8 +148,8 @@ By default, the app has generic favicon. You can override this behavior by provi
| Variable | Type| Description | Compulsoriness | Default value | Example value | | Variable | Type| Description | Compulsoriness | Default value | Example value |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY | `string` | RealFaviconGenerator [API key](https://realfavicongenerator.net/api/) | Required | - | `<your-secret>` | | FAVICON_GENERATOR_API_KEY | `string` | RealFaviconGenerator [API key](https://realfavicongenerator.net/api/) | Required | - | `<your-secret>` |
| NEXT_PUBLIC_FAVICON_MASTER_URL | `string` | - | - | `NEXT_PUBLIC_NETWORK_ICON` | `https://placekitten.com/180/180` | | FAVICON_MASTER_URL | `string` | - | - | `NEXT_PUBLIC_NETWORK_ICON` | `https://placekitten.com/180/180` |
&nbsp; &nbsp;
......
...@@ -12,6 +12,25 @@ const MAIN_DOMAINS = [ ...@@ -12,6 +12,25 @@ const MAIN_DOMAINS = [
getFeaturePayload(config.features.sol2uml)?.api.endpoint, getFeaturePayload(config.features.sol2uml)?.api.endpoint,
].filter(Boolean); ].filter(Boolean);
const getCspReportUrl = () => {
try {
const sentryFeature = config.features.sentry;
if (!sentryFeature.isEnabled || !process.env.SENTRY_CSP_REPORT_URI) {
return;
}
const url = new URL(process.env.SENTRY_CSP_REPORT_URI);
// https://docs.sentry.io/product/security-policy-reporting/#additional-configuration
url.searchParams.set('sentry_environment', sentryFeature.environment);
sentryFeature.release && url.searchParams.set('sentry_release', sentryFeature.release);
return url.toString();
} catch (error) {
return;
}
};
export function app(): CspDev.DirectiveDescriptor { export function app(): CspDev.DirectiveDescriptor {
return { return {
'default-src': [ 'default-src': [
...@@ -110,15 +129,14 @@ export function app(): CspDev.DirectiveDescriptor { ...@@ -110,15 +129,14 @@ export function app(): CspDev.DirectiveDescriptor {
], ],
...((() => { ...((() => {
const sentryFeature = config.features.sentry; if (!config.features.sentry.isEnabled) {
if (!sentryFeature.isEnabled || !sentryFeature.cspReportUrl || config.app.isDev) {
return {}; return {};
} }
return { return {
'report-uri': [ 'report-uri': [
sentryFeature.cspReportUrl, getCspReportUrl(),
], ].filter(Boolean),
}; };
})()), })()),
}; };
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
"lint:eslint": "eslint . --ext .js,.jsx,.ts,.tsx", "lint:eslint": "eslint . --ext .js,.jsx,.ts,.tsx",
"lint:eslint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix", "lint:eslint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
"lint:tsc": "tsc -p ./tsconfig.json", "lint:tsc": "tsc -p ./tsconfig.json",
"lint:envs-validator:dev": "cd ./deploy/tools/envs-validator && ./dev.sh", "lint:envs-validator:test": "cd ./deploy/tools/envs-validator && ./test.sh",
"prepare": "husky install", "prepare": "husky install",
"format-svg": "svgo -r ./icons", "format-svg": "svgo -r ./icons",
"test:pw": "./tools/scripts/pw.sh", "test:pw": "./tools/scripts/pw.sh",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment