diff --git a/.env.example b/.env.example index 34a9c98f4c..7600764337 100644 --- a/.env.example +++ b/.env.example @@ -5,4 +5,4 @@ NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY=xxx NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID=UA-XXXXXX-X NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN=xxx NEXT_PUBLIC_AUTH0_CLIENT_ID=xxx -NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY=xxx \ No newline at end of file +FAVICON_GENERATOR_API_KEY=xxx \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 4cc0e2d97b..763a684cf9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -305,7 +305,7 @@ module.exports = { }, }, { - files: [ '*.config.ts', 'playwright/**', 'deploy/tools/**', 'middleware.ts' ], + files: [ '*.config.ts', 'playwright/**', 'deploy/tools/**', 'middleware.ts', 'nextjs/**' ], rules: { // for configs allow to consume env variables from process.env directly 'no-restricted-properties': [ 0 ], diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 5fa9b0ea95..3a061040a8 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -52,7 +52,7 @@ jobs: run: yarn lint:tsc envs_validation: - name: ENV variables presets validation + name: ENV variables validation runs-on: ubuntu-latest needs: [ code_quality ] steps: @@ -80,13 +80,10 @@ jobs: - name: Install script dependencies run: cd ./deploy/tools/envs-validator && yarn --frozen-lockfile --ignore-optional - - name: Copy secrets file - run: cp ./.env.example ./configs/envs/.env.secrets - - - name: Run validation script + - name: Run validation tests run: | set +e - cd ./deploy/tools/envs-validator && yarn dev + cd ./deploy/tools/envs-validator && yarn test exitcode="$?" echo "exitcode=$exitcode" >> $GITHUB_OUTPUT exit "$exitcode" diff --git a/configs/app/features/sentry.ts b/configs/app/features/sentry.ts index d9b19f12fd..6c21cbd606 100644 --- a/configs/app/features/sentry.ts +++ b/configs/app/features/sentry.ts @@ -14,25 +14,10 @@ const instance = (() => { })(); const environment = getEnvValue('NEXT_PUBLIC_APP_ENV') || 'production'; 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 config: Feature<{ dsn: string; - cspReportUrl: string | undefined; instance: string; release: string | undefined; environment: string; @@ -42,7 +27,6 @@ const config: Feature<{ title, isEnabled: true, dsn, - cspReportUrl, instance, release, environment, diff --git a/deploy/scripts/favicon_generator.sh b/deploy/scripts/favicon_generator.sh index 884b515cd7..4f153dcb0b 100755 --- a/deploy/scripts/favicon_generator.sh +++ b/deploy/scripts/favicon_generator.sh @@ -1,6 +1,6 @@ #!/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" cd ./deploy/tools/favicon-generator diff --git a/deploy/tools/envs-validator/.gitignore b/deploy/tools/envs-validator/.gitignore index 99976e7005..caba20fba5 100644 --- a/deploy/tools/envs-validator/.gitignore +++ b/deploy/tools/envs-validator/.gitignore @@ -2,4 +2,5 @@ /public .env .env.registry +.env.secrets index.js \ No newline at end of file diff --git a/deploy/tools/envs-validator/dev.sh b/deploy/tools/envs-validator/dev.sh deleted file mode 100755 index f9f9175098..0000000000 --- a/deploy/tools/envs-validator/dev.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash - -export NEXT_PUBLIC_GIT_COMMIT_SHA=$(git rev-parse --short HEAD) -export NEXT_PUBLIC_GIT_TAG=$(git describe --tags --abbrev=0) -../../scripts/collect_envs.sh ../../../docs/ENVS.md - -yarn build - -PRESETS=( - "main" - "main.L2" -) - -validate_preset() { - local preset="$1" - secrets_file="../../../configs/envs/.env.secrets" - config_file="../../../configs/envs/.env.${preset}" - - echo - echo "------------------------------------------------" - echo "🧿 Validating preset '$preset'..." - - dotenv \ - -e $config_file \ - -- bash -c '../../scripts/download_assets.sh ./public/assets' - - dotenv \ - -e $config_file \ - -e $secrets_file \ - yarn validate - - if [ $? -eq 0 ]; then - echo "✅ Preset '$preset' is valid." - echo "------------------------------------------------" - echo - return 0 - else - echo "🛑 Preset '$preset' is invalid. Please fix it and run script again." - echo "------------------------------------------------" - echo - return 1 - fi -} - - -for preset in "${PRESETS[@]}"; do - validate_preset "$preset" - if [ $? -eq 1 ]; then - exit 1 - fi -done \ No newline at end of file diff --git a/deploy/tools/envs-validator/index.ts b/deploy/tools/envs-validator/index.ts index 405f4b9178..ad70d6f540 100644 --- a/deploy/tools/envs-validator/index.ts +++ b/deploy/tools/envs-validator/index.ts @@ -3,12 +3,15 @@ import fs from 'fs'; import path from 'path'; import type { ValidationError } from 'yup'; +import { buildExternalAssetFilePath } from '../../../configs/app/utils'; import schema from './schema'; +const silent = process.argv.includes('--silent'); + run(); async function run() { - console.log(); + !silent && console.log(); try { const appEnvs = Object.entries(process.env) .filter(([ key ]) => key.startsWith('NEXT_PUBLIC_')) @@ -26,25 +29,22 @@ async function run() { } async function validateEnvs(appEnvs: Record) { - console.log(`🌀 Validating ENV variables values...`); + !silent && console.log(`🌀 Validating ENV variables values...`); try { // replace ENVs with external JSON files content - appEnvs.NEXT_PUBLIC_FEATURED_NETWORKS = await getExternalJsonContent( - './public/assets/featured_networks.json', - appEnvs.NEXT_PUBLIC_FEATURED_NETWORKS, - ) || '[]'; - appEnvs.NEXT_PUBLIC_MARKETPLACE_CONFIG_URL = await getExternalJsonContent( - './public/assets/marketplace_config.json', - appEnvs.NEXT_PUBLIC_MARKETPLACE_CONFIG_URL, - ) || '[]'; - appEnvs.NEXT_PUBLIC_FOOTER_LINKS = await getExternalJsonContent( - './public/assets/footer_links.json', - appEnvs.NEXT_PUBLIC_FOOTER_LINKS, - ) || '[]'; + const envsWithJsonConfig = [ + 'NEXT_PUBLIC_FEATURED_NETWORKS', + 'NEXT_PUBLIC_MARKETPLACE_CONFIG_URL', + 'NEXT_PUBLIC_FOOTER_LINKS', + ]; + + for await (const envName of envsWithJsonConfig) { + appEnvs[envName] = await(appEnvs[envName] ? getExternalJsonContent(envName) : Promise.resolve()) || '[]'; + } await schema.validate(appEnvs, { stripUnknown: false, abortEarly: false }); - console.log('👍 All good!'); + !silent && console.log('👍 All good!'); } catch (_error) { if (typeof _error === 'object' && _error !== null && 'errors' in _error) { console.log('🚨 ENVs validation failed with the following errors:'); @@ -59,15 +59,12 @@ async function validateEnvs(appEnvs: Record) { throw _error; } - console.log(); + !silent && console.log(); } -async function getExternalJsonContent(fileName: string, envValue: string): Promise { +async function getExternalJsonContent(envName: string): Promise { return new Promise((resolve, reject) => { - if (!envValue) { - resolve(); - return; - } + const fileName = `./public${ buildExternalAssetFilePath(envName, '.json') }`; fs.readFile(path.resolve(__dirname, fileName), 'utf8', (err, data) => { if (err) { @@ -83,7 +80,7 @@ async function getExternalJsonContent(fileName: string, envValue: string): Promi async function checkPlaceholdersCongruity(envsMap: Record) { 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 buildTimeEnvs = await getEnvsPlaceholders(path.resolve(__dirname, '.env')); @@ -108,7 +105,7 @@ async function checkPlaceholdersCongruity(envsMap: Record) { throw new Error(); } - console.log('👍 All good!\n'); + !silent && console.log('👍 All good!\n'); } catch (error) { console.log('🚨 Congruity check failed.\n'); throw error; diff --git a/deploy/tools/envs-validator/package.json b/deploy/tools/envs-validator/package.json index 1f6b83ae2e..1cc1803950 100644 --- a/deploy/tools/envs-validator/package.json +++ b/deploy/tools/envs-validator/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "yarn webpack-cli -c ./webpack.config.js", "validate": "node ./index.js", - "dev": "./dev.sh" + "test": "./test.sh" }, "dependencies": { "ts-loader": "^9.4.4", diff --git a/deploy/tools/envs-validator/schema.ts b/deploy/tools/envs-validator/schema.ts index cbda80fada..6d99d794ef 100644 --- a/deploy/tools/envs-validator/schema.ts +++ b/deploy/tools/envs-validator/schema.ts @@ -438,7 +438,6 @@ const schema = yup NEXT_PUBLIC_RE_CAPTCHA_APP_SITE_KEY: yup.string(), NEXT_PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: yup.string(), NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN: yup.string(), - NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY: yup.string(), // Misc NEXT_PUBLIC_USE_NEXT_JS_PROXY: yup.boolean(), diff --git a/deploy/tools/envs-validator/test.sh b/deploy/tools/envs-validator/test.sh new file mode 100755 index 0000000000..179ef25bc9 --- /dev/null +++ b/deploy/tools/envs-validator/test.sh @@ -0,0 +1,49 @@ +#!/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_TAG=$(git describe --tags --abbrev=0) +../../scripts/collect_envs.sh ../../../docs/ENVS.md +cp ../../../.env.example ${secrets_file} + +# Copy test assets +mkdir -p "./public/assets" +cp -r ${test_folder}/assets ./public/ + +# Build validator script +yarn build + +validate_file() { + local test_file="$1" + + echo + echo "🧿 Validating file '$test_file'..." + + dotenv \ + -e $test_file \ + -e $common_file \ + -e $secrets_file \ + yarn run validate -- --silent + + if [ $? -eq 0 ]; then + echo "👍 All good!" + return 0 + else + echo "🛑 The file is invalid. Please fix errors and run script again." + echo + return 1 + fi +} + +test_files=($(find "$test_folder" -maxdepth 1 -type f | grep -vE '\/\.env\.common$')) + +for file in "${test_files[@]}"; do + validate_file "$file" + if [ $? -eq 1 ]; then + exit 1 + fi +done \ No newline at end of file diff --git a/deploy/tools/envs-validator/test/.env.adbutler b/deploy/tools/envs-validator/test/.env.adbutler new file mode 100644 index 0000000000..7877a7740c --- /dev/null +++ b/deploy/tools/envs-validator/test/.env.adbutler @@ -0,0 +1,3 @@ +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 diff --git a/deploy/tools/envs-validator/test/.env.base b/deploy/tools/envs-validator/test/.env.base new file mode 100644 index 0000000000..bd90533eff --- /dev/null +++ b/deploy/tools/envs-validator/test/.env.base @@ -0,0 +1,52 @@ +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='Hello' +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 diff --git a/deploy/tools/envs-validator/test/.env.beacon_chain b/deploy/tools/envs-validator/test/.env.beacon_chain new file mode 100644 index 0000000000..f0800e9af3 --- /dev/null +++ b/deploy/tools/envs-validator/test/.env.beacon_chain @@ -0,0 +1,2 @@ +NEXT_PUBLIC_HAS_BEACON_CHAIN=true +NEXT_PUBLIC_BEACON_CHAIN_CURRENCY_SYMBOL=aETH \ No newline at end of file diff --git a/deploy/tools/envs-validator/test/.env.common b/deploy/tools/envs-validator/test/.env.common new file mode 100644 index 0000000000..1f900840ff --- /dev/null +++ b/deploy/tools/envs-validator/test/.env.common @@ -0,0 +1,7 @@ +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 diff --git a/deploy/tools/envs-validator/test/.env.rollup b/deploy/tools/envs-validator/test/.env.rollup new file mode 100644 index 0000000000..cfae86c8a2 --- /dev/null +++ b/deploy/tools/envs-validator/test/.env.rollup @@ -0,0 +1,3 @@ +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 diff --git a/deploy/tools/envs-validator/test/assets/featured_networks.json b/deploy/tools/envs-validator/test/assets/featured_networks.json new file mode 100644 index 0000000000..83b9088843 --- /dev/null +++ b/deploy/tools/envs-validator/test/assets/featured_networks.json @@ -0,0 +1,22 @@ +[ + { + "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 diff --git a/deploy/tools/envs-validator/test/assets/footer_links.json b/deploy/tools/envs-validator/test/assets/footer_links.json new file mode 100644 index 0000000000..d3f7e7d437 --- /dev/null +++ b/deploy/tools/envs-validator/test/assets/footer_links.json @@ -0,0 +1,28 @@ +[ + { + "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 diff --git a/deploy/tools/envs-validator/test/assets/marketplace_config.json b/deploy/tools/envs-validator/test/assets/marketplace_config.json new file mode 100644 index 0000000000..0b142b7a24 --- /dev/null +++ b/deploy/tools/envs-validator/test/assets/marketplace_config.json @@ -0,0 +1,25 @@ +[ + { + "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" + } + ] diff --git a/deploy/tools/envs-validator/tsconfig.json b/deploy/tools/envs-validator/tsconfig.json index a3ffc54e19..a169faac5c 100644 --- a/deploy/tools/envs-validator/tsconfig.json +++ b/deploy/tools/envs-validator/tsconfig.json @@ -8,7 +8,13 @@ "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": { "verbose": true, "resolveFullPaths": true, diff --git a/deploy/tools/favicon-generator/script.sh b/deploy/tools/favicon-generator/script.sh index 098e336b8f..69145399ed 100755 --- a/deploy/tools/favicon-generator/script.sh +++ b/deploy/tools/favicon-generator/script.sh @@ -8,17 +8,17 @@ if [ -z "$MASTER_URL" ]; then exit 1 fi -# Check if NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY is provided -if [ -z "$NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY" ]; then - echo "🛑 Error: NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY variable is not provided." +# Check if FAVICON_GENERATOR_API_KEY is provided +if [ -z "$FAVICON_GENERATOR_API_KEY" ]; then + echo "🛑 Error: FAVICON_GENERATOR_API_KEY variable is not provided." exit 1 fi -# Mask the NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY to display only the first 8 characters -API_KEY_MASKED="${NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY:0:8}***" +# Mask the FAVICON_GENERATOR_API_KEY to display only the first 8 characters +API_KEY_MASKED="${FAVICON_GENERATOR_API_KEY:0:8}***" echo "🆗 The following variables are provided:" echo " MASTER_URL: $MASTER_URL" -echo " NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY: $API_KEY_MASKED" +echo " FAVICON_GENERATOR_API_KEY: $API_KEY_MASKED" echo # RealFaviconGenerator API endpoint URL @@ -34,7 +34,7 @@ CONFIG_TEMPLATE_FILE="config.template.json" CONFIG_FILE="config.json" # Replace and 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_VALUE|" -e "s||$MASTER_URL|" "$CONFIG_TEMPLATE_FILE" > "$CONFIG_FILE" # Make the API POST request with JSON data from the config file diff --git a/deploy/values/l2-optimism-goerli/values.yaml b/deploy/values/l2-optimism-goerli/values.yaml index 2d4317b2d4..b4d28dcc45 100644 --- a/deploy/values/l2-optimism-goerli/values.yaml +++ b/deploy/values/l2-optimism-goerli/values.yaml @@ -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_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_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 diff --git a/deploy/values/main/values.yaml b/deploy/values/main/values.yaml index 463a5f8324..c178a6ffbf 100644 --- a/deploy/values/main/values.yaml +++ b/deploy/values/main/values.yaml @@ -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_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_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 diff --git a/deploy/values/review-l2/values.yaml.gotmpl b/deploy/values/review-l2/values.yaml.gotmpl index 3efc4bc89a..8d0b23d528 100644 --- a/deploy/values/review-l2/values.yaml.gotmpl +++ b/deploy/values/review-l2/values.yaml.gotmpl @@ -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 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 NEXT_PUBLIC_OG_IMAGE_URL: _default: https://github.com/blockscout/frontend-configs/blob/main/configs/og-images/base-goerli.png?raw=true diff --git a/deploy/values/review/values.yaml.gotmpl b/deploy/values/review/values.yaml.gotmpl index fe1e547772..348f353f8b 100644 --- a/deploy/values/review/values.yaml.gotmpl +++ b/deploy/values/review/values.yaml.gotmpl @@ -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 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 NEXT_PUBLIC_WEB3_WALLETS: _default: "['token_pocket','coinbase','metamask']" diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 6362e067c1..ded9059c3c 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -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/review-l2/values.yaml.gotmpl` - review development environment for L2 networks - `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` - install deps with `yarn` command - - change `PRESETS` array in `dev.sh` script file accordingly - - run `yarn dev` command and see the validation result - - *Please* do not commit your changes in the `dev.sh` file since it is also used in the CI workflow -6. Don't forget to mention in the PR notes that new ENV variable was added + - add your variable into `./test/.env.base` test preset or create a new test preset if needed + - if your variable contains a link to the external JSON config file: + - 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`) + - 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   diff --git a/docs/ENVS.md b/docs/ENVS.md index a3a39f37f7..a455c28d1e 100644 --- a/docs/ENVS.md +++ b/docs/ENVS.md @@ -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 | | --- | --- | --- | --- | --- | --- | -| NEXT_PUBLIC_FAVICON_GENERATOR_API_KEY | `string` | RealFaviconGenerator [API key](https://realfavicongenerator.net/api/) | Required | - | `` | -| NEXT_PUBLIC_FAVICON_MASTER_URL | `string` | - | - | `NEXT_PUBLIC_NETWORK_ICON` | `https://placekitten.com/180/180` | +| FAVICON_GENERATOR_API_KEY | `string` | RealFaviconGenerator [API key](https://realfavicongenerator.net/api/) | Required | - | `` | +| FAVICON_MASTER_URL | `string` | - | - | `NEXT_PUBLIC_NETWORK_ICON` | `https://placekitten.com/180/180` |   diff --git a/nextjs/csp/policies/app.ts b/nextjs/csp/policies/app.ts index de4c3b4ac3..ef338a22dc 100644 --- a/nextjs/csp/policies/app.ts +++ b/nextjs/csp/policies/app.ts @@ -12,6 +12,25 @@ const MAIN_DOMAINS = [ getFeaturePayload(config.features.sol2uml)?.api.endpoint, ].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 { return { 'default-src': [ @@ -110,15 +129,14 @@ export function app(): CspDev.DirectiveDescriptor { ], ...((() => { - const sentryFeature = config.features.sentry; - if (!sentryFeature.isEnabled || !sentryFeature.cspReportUrl || config.app.isDev) { + if (!config.features.sentry.isEnabled) { return {}; } return { 'report-uri': [ - sentryFeature.cspReportUrl, - ], + getCspReportUrl(), + ].filter(Boolean), }; })()), }; diff --git a/package.json b/package.json index 874cf7876c..3ea3330a00 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "lint:eslint": "eslint . --ext .js,.jsx,.ts,.tsx", "lint:eslint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix", "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", "format-svg": "svgo -r ./icons", "test:pw": "./tools/scripts/pw.sh",