From e1b3fe2df5d1077661a98049ba7f0f7928aa2ffa Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Fri, 10 Feb 2023 02:15:24 +0100 Subject: [PATCH] restrict `0.0.0.0` in code files and `0.0.0.0` in `.env.template` files (#1323) --- .eslintrc.cjs | 12 ++++++++++- .github/workflows/lint.yaml | 3 +++ package.json | 2 ++ pnpm-lock.yaml | 39 ++++++++++++++++++++++++++++++++++- scripts/check-env-template.ts | 32 ++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 scripts/check-env-template.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 8d48a9225..bba25e800 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,5 +1,6 @@ /* eslint-env node */ const guildConfig = require('@theguild/eslint-config/base'); +const { REACT_RESTRICTED_SYNTAX, RESTRICTED_SYNTAX } = require('@theguild/eslint-config/constants'); const rulesToExtends = Object.fromEntries( Object.entries(guildConfig.rules).filter(([key]) => @@ -16,11 +17,18 @@ const rulesToExtends = Object.fromEntries( 'react/self-closing-comp', 'prefer-const', 'no-extra-boolean-cast', - 'no-restricted-syntax', ].includes(key), ), ); +const HIVE_RESTRICTED_SYNTAX = [ + { + // ❌ '0.0.0.0' or `0.0.0.0` + selector: ':matches(Literal[value="0.0.0.0"], TemplateElement[value.raw="0.0.0.0"])', + message: 'Use "::" to make it compatible with both IPv4 and IPv6', + }, +]; + module.exports = { reportUnusedDisableDirectives: true, ignorePatterns: [ @@ -65,6 +73,7 @@ module.exports = { '@typescript-eslint/no-floating-promises': 'error', '@typescript-eslint/no-unnecessary-type-assertion': 'error', ...rulesToExtends, + 'no-restricted-syntax': ['error', ...HIVE_RESTRICTED_SYNTAX, ...RESTRICTED_SYNTAX], // 🚨 The following rules needs to be fixed and was temporarily disabled to avoid printing warning '@typescript-eslint/no-explicit-any': 'off', @@ -99,6 +108,7 @@ module.exports = { 'react/no-unknown-property': 'off', 'jsx-a11y/anchor-is-valid': ['off', { components: ['Link', 'NextLink'] }], 'jsx-a11y/alt-text': ['warn', { elements: ['img'], img: ['Image', 'NextImage'] }], + 'no-restricted-syntax': ['error', ...HIVE_RESTRICTED_SYNTAX, ...REACT_RESTRICTED_SYNTAX], // TODO: enable below rules👇 '@typescript-eslint/consistent-type-imports': ['off', { prefer: 'no-type-imports' }], diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 77125d63c..80c4a34ea 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -12,6 +12,9 @@ jobs: - name: setup environment uses: ./.github/actions/setup + - name: lint .env.template files + run: pnpm lint:env-template + - name: eslint cache uses: actions/cache@v3 with: diff --git a/package.json b/package.json index 297023252..07e75aef5 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "generate": "pnpm --filter @hive/storage db:generate && pnpm graphql:generate", "graphql:generate": "graphql-codegen", "lint": "eslint --cache --ignore-path .gitignore \"{packages,cypress}/**/*.{ts,tsx}\"", + "lint:env-template": "tsx scripts/check-env-template.ts", "lint:fix": "pnpm lint --fix", "lint:prettier": "prettier --cache --check .", "local:setup": "docker-compose -f ./docker/docker-compose.dev.yml up -d --remove-orphans && pnpm --filter @hive/migrations db:init", @@ -92,6 +93,7 @@ "ts-jest": "29.0.5", "ts-node": "10.9.1", "tsup": "6.6.0", + "tsx": "3.12.3", "turbo": "1.7.4", "typescript": "4.9.5" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 66d8e1143..8c5dd8d2e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -83,6 +83,7 @@ importers: ts-jest: 29.0.5 ts-node: 10.9.1 tsup: 6.5.0 + tsx: 3.12.3 turbo: 1.7.4 typescript: 4.9.5 devDependencies: @@ -132,6 +133,7 @@ importers: ts-jest: 29.0.5_xvkg46limlf5bbm7x5z7xzp47q ts-node: 10.9.1_fitjlvgw3uly4vbg54vdujb7vy tsup: 6.5.0_arb6tv3bymv5hkfd2xmjxdai7u + tsx: 3.12.3 turbo: 1.7.4 typescript: 4.9.5 @@ -5967,6 +5969,27 @@ packages: tslib: 2.5.0 dev: false + /@esbuild-kit/cjs-loader/2.4.2: + resolution: {integrity: sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==} + dependencies: + '@esbuild-kit/core-utils': 3.1.0 + get-tsconfig: 4.4.0 + dev: true + + /@esbuild-kit/core-utils/3.1.0: + resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==} + dependencies: + esbuild: 0.17.6 + source-map-support: 0.5.21 + dev: true + + /@esbuild-kit/esm-loader/2.5.5: + resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==} + dependencies: + '@esbuild-kit/core-utils': 3.1.0 + get-tsconfig: 4.4.0 + dev: true + /@esbuild/android-arm/0.15.15: resolution: {integrity: sha512-JJjZjJi2eBL01QJuWjfCdZxcIgot+VoK6Fq7eKF9w4YHm9hwl7nhBR1o2Wnt/WcANk5l9SkpvrldW1PLuXxcbw==} engines: {node: '>=12'} @@ -17172,6 +17195,10 @@ packages: call-bind: 1.0.2 get-intrinsic: 1.1.3 + /get-tsconfig/4.4.0: + resolution: {integrity: sha512-0Gdjo/9+FzsYhXCEFueo2aY1z1tpXrxWZzP7k8ul9qt1U5o8rYJwTJYmaeHdrVosYIVYkOy2iwCJ9FdpocJhPQ==} + dev: true + /getos/3.2.1: resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} dependencies: @@ -25041,7 +25068,6 @@ packages: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - dev: false /source-map/0.5.6: resolution: {integrity: sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==} @@ -26250,6 +26276,17 @@ packages: typescript: 4.9.5 dev: true + /tsx/3.12.3: + resolution: {integrity: sha512-Wc5BFH1xccYTXaQob+lEcimkcb/Pq+0en2s+ruiX0VEIC80nV7/0s7XRahx8NnsoCnpCVUPz8wrqVSPi760LkA==} + hasBin: true + dependencies: + '@esbuild-kit/cjs-loader': 2.4.2 + '@esbuild-kit/core-utils': 3.1.0 + '@esbuild-kit/esm-loader': 2.5.5 + optionalDependencies: + fsevents: 2.3.2 + dev: true + /tty-table/4.1.6: resolution: {integrity: sha512-kRj5CBzOrakV4VRRY5kUWbNYvo/FpOsz65DzI5op9P+cHov3+IqPbo1JE1ZnQGkHdZgNFDsrEjrfqqy/Ply9fw==} engines: {node: '>=8.0.0'} diff --git a/scripts/check-env-template.ts b/scripts/check-env-template.ts new file mode 100644 index 000000000..a0d3f92c9 --- /dev/null +++ b/scripts/check-env-template.ts @@ -0,0 +1,32 @@ +import { readFile } from 'node:fs/promises'; +import fg from 'fast-glob'; + +const FORBIDDEN_IP = '0.0.0.0'; +const ALLOWED_IP = 'localhost'; + +const envTemplatePaths = await fg('**/.env.template', { + cwd: process.cwd(), + ignore: ['**/node_modules'], +}); + +for (const envPath of envTemplatePaths) { + const file = await readFile(envPath, 'utf8'); + const entry = file + .split('\n') + .filter(line => line && !line.startsWith('#')) + .map(keyValue => { + const [key, value] = keyValue.split('='); + return [key, value.match(/(["'])((?:\1|.)*?)\1/)?.[2] || value]; + }); + + for (const [key, value] of entry) { + if (value.includes(FORBIDDEN_IP)) { + throw new Error(`Error while validating "${key}" in ${envPath}. + +Use "${ALLOWED_IP}" to make it compatible with both IPv4 and IPv6. + +Replace: ${value} by ${value.replace(FORBIDDEN_IP, ALLOWED_IP)} +`); + } + } +}