diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000..d3337c5373
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,24 @@
+# Common file for apps that rely on root context
+.git
+.github
+.husky
+audits
+docs
+scripts
+**/node_modules
+**/build
+**/dist
+
+# Core package artifacts
+# Hardhat files
+**/abis
+**/artifacts
+**/cache
+**/.deps
+# TypeScript bindings output directory
+**/typechain-types
+
+# Docker-related
+.dockerignore
+**/Dockerfile*
+**/docker-compose*
diff --git a/.gitignore b/.gitignore
index 03a667ba70..0fb820a136 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,10 +3,8 @@ node_modules
# dotenv environment variable files
.env
-.env.development.local
-.env.test.local
-.env.production.local
.env.local
+.env.*.local
# Log files
npm-debug.log*
diff --git a/packages/apps/human-app/frontend/.env.example b/packages/apps/human-app/frontend/.env.example
index 9239e2bbad..2035eeae60 100644
--- a/packages/apps/human-app/frontend/.env.example
+++ b/packages/apps/human-app/frontend/.env.example
@@ -10,8 +10,6 @@ VITE_HUMAN_PROTOCOL_HELP_URL= #string
VITE_HUMAN_SUPPORT_EMAIL= #string
# link to human web page
VITE_HUMAN_PROTOCOL_URL= #string
-# link to "Learn more" in wallet connect modal
-VITE_WALLET_CONNECT_MODAL_LINK= #string
# link to human web page in main page navbar
VITE_NAVBAR__LINK__PROTOCOL_URL= #string
# link to human web page section in main page navbar
diff --git a/packages/apps/human-app/frontend/Dockerfile b/packages/apps/human-app/frontend/Dockerfile
new file mode 100644
index 0000000000..8473ebefe0
--- /dev/null
+++ b/packages/apps/human-app/frontend/Dockerfile
@@ -0,0 +1,28 @@
+# Using bullseye instead of slim because it needs Python and build tools for node-gyp
+FROM node:18-bullseye
+ARG APP_PATH=packages/apps/human-app/frontend
+
+# Create app directory
+WORKDIR /usr/src/app
+
+# Copy expected yarn dist
+COPY .yarn ./.yarn
+COPY .yarnrc ./
+# Copy files for deps installation
+COPY package.json yarn.lock ./
+COPY ${APP_PATH}/package.json ./${APP_PATH}/package.json
+# Some deps are referenced as "*", so we need to build them
+COPY tsconfig.json ./
+COPY packages/core ./packages/core
+COPY packages/sdk ./packages/sdk
+
+RUN yarn install
+
+# Copy everything else to ensure proper build process
+COPY . .
+
+WORKDIR ./${APP_PATH}
+RUN yarn build
+
+# Start the server using the build
+CMD [ "yarn", "start:prod" ]
\ No newline at end of file
diff --git a/packages/apps/human-app/frontend/package.json b/packages/apps/human-app/frontend/package.json
index e814adced6..5a0e437ffb 100644
--- a/packages/apps/human-app/frontend/package.json
+++ b/packages/apps/human-app/frontend/package.json
@@ -23,6 +23,7 @@
"@human-protocol/sdk": "*",
"@mui/icons-material": "^6.2.0",
"@mui/material": "^5.16.7",
+ "@mui/x-date-pickers": "^7.23.6",
"@reown/appkit": "1.3.2",
"@reown/appkit-adapter-wagmi": "1.3.2",
"@synaps-io/verify-sdk": "^4.0.45",
@@ -32,7 +33,7 @@
"i18next": "^23.8.2",
"jwt-decode": "^4.0.0",
"lodash": "^4.17.21",
- "material-react-table": "^3.0.1",
+ "material-react-table": "3.0.1",
"mui-image": "^1.0.7",
"notistack": "^3.0.1",
"query-string": "^9.0.0",
@@ -43,6 +44,7 @@
"react-imask": "^7.4.0",
"react-number-format": "^5.4.3",
"react-router-dom": "^6.22.0",
+ "serve": "^14.2.4",
"viem": "^2.21.44",
"vite-plugin-svgr": "^4.2.0",
"wagmi": "2.14.6",
diff --git a/packages/apps/human-app/frontend/src/modules/auth-web3/components/wallet-connect-modal.tsx b/packages/apps/human-app/frontend/src/modules/auth-web3/components/wallet-connect-modal.tsx
index 89ac0c446e..8a5b8f8bd8 100644
--- a/packages/apps/human-app/frontend/src/modules/auth-web3/components/wallet-connect-modal.tsx
+++ b/packages/apps/human-app/frontend/src/modules/auth-web3/components/wallet-connect-modal.tsx
@@ -1,12 +1,10 @@
import { t } from 'i18next';
import { Grid, Typography } from '@mui/material';
import { Trans } from 'react-i18next';
-import { Link } from 'react-router-dom';
import { useEffect } from 'react';
import { Button } from '@/shared/components/ui/button';
import { ConnectWalletBtn } from '@/shared/components/ui/connect-wallet-btn';
import { useModalStore } from '@/shared/components/ui/modal/modal.store';
-import { env } from '@/shared/env';
import { useWalletConnect } from '@/shared/hooks/use-wallet-connect';
export function WalletConnectModal() {
@@ -46,21 +44,7 @@ export function WalletConnectModal() {
}}
>
-
- ),
- }}
- i18nKey="walletConnectModal.paragraph"
- />
+
{t('walletConnectModal.connectBtn')}
diff --git a/packages/apps/human-app/frontend/src/shared/env.ts b/packages/apps/human-app/frontend/src/shared/env.ts
index 5ba7f86733..a65c1bb2f5 100644
--- a/packages/apps/human-app/frontend/src/shared/env.ts
+++ b/packages/apps/human-app/frontend/src/shared/env.ts
@@ -10,7 +10,6 @@ const envSchema = z.object({
VITE_NAVBAR__LINK__HOW_IT_WORK_URL: z.string(),
VITE_HUMAN_SUPPORT_EMAIL: z.string(),
VITE_HUMAN_PROTOCOL_HELP_URL: z.string(),
- VITE_WALLET_CONNECT_MODAL_LINK: z.string(),
VITE_H_CAPTCHA_SITE_KEY: z.string(),
VITE_HMT_DAILY_SPENT_LIMIT: z
.string()
@@ -59,7 +58,6 @@ try {
validEnvs = envSchema.parse(import.meta.env);
} catch (error) {
if (error instanceof ZodError) {
- console.error('Invalid .env file');
error.issues.forEach((issue) => {
console.error('Invalid env:', issue.path.join());
console.error(issue);
diff --git a/packages/apps/human-app/frontend/src/shared/i18n/en.json b/packages/apps/human-app/frontend/src/shared/i18n/en.json
index 3d9ea2209f..483f116631 100644
--- a/packages/apps/human-app/frontend/src/shared/i18n/en.json
+++ b/packages/apps/human-app/frontend/src/shared/i18n/en.json
@@ -394,7 +394,7 @@
},
"walletConnectModal": {
"header": "Connect Wallet",
- "paragraph": "HUMAN App is a multichain platform, please provide a wallet address which will be compatible with different chains. <1>Learn more or FAQ link.1>",
+ "paragraph": "HUMAN App is a multichain platform, please provide a wallet address which will be compatible with different chains.",
"connectBtn": "Connect Wallet",
"cancelBtn": "Cancel"
},
diff --git a/packages/apps/human-app/server/.dockerignore b/packages/apps/human-app/server/.dockerignore
deleted file mode 100644
index 1d7d55faac..0000000000
--- a/packages/apps/human-app/server/.dockerignore
+++ /dev/null
@@ -1,5 +0,0 @@
-Dockerfile
-.dockerignore
-node_modules
-npm-debug.log
-dist
\ No newline at end of file
diff --git a/packages/apps/human-app/server/Dockerfile b/packages/apps/human-app/server/Dockerfile
index 2d5efe5498..6e355e5ccb 100644
--- a/packages/apps/human-app/server/Dockerfile
+++ b/packages/apps/human-app/server/Dockerfile
@@ -1,17 +1,27 @@
-# Base image
-FROM node:18
+FROM node:18-slim
+ARG APP_PATH=packages/apps/human-app/server
# Create app directory
WORKDIR /usr/src/app
-# Bundle app source
-COPY . .
+# Copy expected yarn dist
+COPY .yarn ./.yarn
+COPY .yarnrc ./
+# Copy files for deps installation
+COPY package.json yarn.lock ./
+COPY ${APP_PATH}/package.json ./${APP_PATH}/package.json
+# Some deps are referenced as "*", so we need to build them
+COPY tsconfig.json ./
+COPY packages/core ./packages/core
+COPY packages/sdk ./packages/sdk
-# Install app dependencies
RUN yarn install
-# Creates a "dist" folder with the production build
-RUN yarn workspace @human-protocol/human-app-server build
+# Copy everything else to ensure proper build process
+COPY . .
+
+WORKDIR ./${APP_PATH}
+RUN yarn build
-# Start the server using the production build
-CMD [ "node", "packages/apps/human-app/server/dist/src/main.js" ]
+# Start the server using the build
+CMD [ "yarn", "start:prod" ]
\ No newline at end of file
diff --git a/packages/apps/human-app/server/package.json b/packages/apps/human-app/server/package.json
index 1889a97d7f..b8a6db3c0c 100644
--- a/packages/apps/human-app/server/package.json
+++ b/packages/apps/human-app/server/package.json
@@ -30,6 +30,8 @@
"@nestjs/common": "^10.2.7",
"@nestjs/config": "^3.1.1",
"@nestjs/core": "^10.3.10",
+ "@nestjs/platform-express": "^10.3.10",
+ "@nestjs/schedule": "^4.0.1",
"@nestjs/swagger": "^7.4.2",
"@nestjs/terminus": "^10.2.3",
"cache-manager": "^5.4.0",
@@ -38,7 +40,10 @@
"class-validator": "^0.14.1",
"ethers": "^6.12.1",
"joi": "^17.13.3",
+ "jsonwebtoken": "^9.0.2",
+ "jwt-decode": "^4.0.0",
"lodash": "^4.17.21",
+ "reflect-metadata": "^0.2.2",
"rxjs": "^7.2.0"
},
"devDependencies": {
@@ -47,6 +52,8 @@
"@nestjs/testing": "^10.4.6",
"@types/express": "^4.17.13",
"@types/jest": "29.5.12",
+ "@types/jsonwebtoken": "^9.0.7",
+ "@types/lodash": "^4.17.14",
"@types/node": "22.10.5",
"@types/supertest": "^2.0.15",
"@typescript-eslint/eslint-plugin": "^5.0.0",
diff --git a/packages/apps/human-app/server/src/app.module.ts b/packages/apps/human-app/server/src/app.module.ts
index 35c816d192..58ec0021da 100644
--- a/packages/apps/human-app/server/src/app.module.ts
+++ b/packages/apps/human-app/server/src/app.module.ts
@@ -58,6 +58,7 @@ const JOI_BOOLEAN_STRING_SCHEMA = Joi.string().valid('true', 'false');
REPUTATION_ORACLE_ADDRESS: Joi.string().required(),
REDIS_PORT: Joi.number().required(),
REDIS_HOST: Joi.string().required(),
+ REDIS_DB: Joi.number(),
RPC_URL: Joi.string().required(),
HCAPTCHA_LABELING_STATS_API_URL: Joi.string().required(),
HCAPTCHA_LABELING_VERIFY_API_URL: Joi.string().required(),
diff --git a/packages/apps/human-app/server/src/common/config/cache-factory.config.ts b/packages/apps/human-app/server/src/common/config/cache-factory.config.ts
index 31f98f895a..53b06b8793 100644
--- a/packages/apps/human-app/server/src/common/config/cache-factory.config.ts
+++ b/packages/apps/human-app/server/src/common/config/cache-factory.config.ts
@@ -21,6 +21,7 @@ export const CacheFactoryConfig: CacheModuleAsyncOptions = {
host: configService.cacheHost,
port: configService.cachePort,
},
+ database: configService.cacheDbNumber,
disableOfflineQueue: true,
});
diff --git a/packages/apps/human-app/server/src/common/config/environment-config.service.ts b/packages/apps/human-app/server/src/common/config/environment-config.service.ts
index 8621f011fa..fd7b513dce 100644
--- a/packages/apps/human-app/server/src/common/config/environment-config.service.ts
+++ b/packages/apps/human-app/server/src/common/config/environment-config.service.ts
@@ -92,6 +92,13 @@ export class EnvironmentConfigService {
return this.configService.getOrThrow('REDIS_HOST');
}
+ /**
+ * The DB number of the Redis cache server
+ */
+ get cacheDbNumber(): number {
+ return this.configService.get('REDIS_DB', 0);
+ }
+
/**
* The cache time-to-live (TTL) for oracle statistics.
* Default: 12 hours
diff --git a/packages/apps/job-launcher/client/Dockerfile b/packages/apps/job-launcher/client/Dockerfile
new file mode 100644
index 0000000000..ece5e34e0b
--- /dev/null
+++ b/packages/apps/job-launcher/client/Dockerfile
@@ -0,0 +1,28 @@
+# Using bullseye instead of slim because it needs Python and build tools for node-gyp
+FROM node:18-bullseye
+ARG APP_PATH=packages/apps/job-launcher/client
+
+# Create app directory
+WORKDIR /usr/src/app
+
+# Copy expected yarn dist
+COPY .yarn ./.yarn
+COPY .yarnrc ./
+# Copy files for deps installation
+COPY package.json yarn.lock ./
+COPY ${APP_PATH}/package.json ./${APP_PATH}/package.json
+# Some deps are referenced as "*", so we need to build them
+COPY tsconfig.json ./
+COPY packages/core ./packages/core
+COPY packages/sdk ./packages/sdk
+
+RUN yarn install
+
+# Copy everything else to ensure proper build process
+COPY . .
+
+WORKDIR ./${APP_PATH}
+RUN yarn build
+
+# Start the server using the build
+CMD [ "yarn", "start:prod" ]
\ No newline at end of file
diff --git a/packages/apps/job-launcher/server/.env.example b/packages/apps/job-launcher/server/.env.example
index 45eabf1bc0..84e8cb920e 100644
--- a/packages/apps/job-launcher/server/.env.example
+++ b/packages/apps/job-launcher/server/.env.example
@@ -68,6 +68,3 @@ STRIPE_APP_INFO_URL=
# Sendgrid
SENDGRID_API_KEY=
-
-# Cron Job Secret
-CRON_SECRET="cron-secret"
diff --git a/packages/apps/job-launcher/server/Dockerfile b/packages/apps/job-launcher/server/Dockerfile
index 51a61a583a..63a89f533d 100644
--- a/packages/apps/job-launcher/server/Dockerfile
+++ b/packages/apps/job-launcher/server/Dockerfile
@@ -1,17 +1,27 @@
-# Base image
-FROM node:18
+FROM node:18-slim
+ARG APP_PATH=packages/apps/job-launcher/server
# Create app directory
WORKDIR /usr/src/app
-# Bundle app source
-COPY . .
+# Copy expected yarn dist
+COPY .yarn ./.yarn
+COPY .yarnrc ./
+# Copy files for deps installation
+COPY package.json yarn.lock ./
+COPY ${APP_PATH}/package.json ./${APP_PATH}/package.json
+# Some deps are referenced as "*", so we need to build them
+COPY tsconfig.json ./
+COPY packages/core ./packages/core
+COPY packages/sdk ./packages/sdk
-# Install app dependencies
RUN yarn install
-# Creates a "dist" folder with the production build
-RUN yarn workspace @human-protocol/job-launcher-server build
+# Copy everything else to ensure proper build process
+COPY . .
+
+WORKDIR ./${APP_PATH}
+RUN yarn build
-# Start the server using the production build
-CMD [ "node", "packages/apps/job-launcher/server/dist/src/main.js" ]
+# Start the server using the build
+CMD [ "yarn", "start:prod" ]
\ No newline at end of file
diff --git a/packages/apps/job-launcher/server/package.json b/packages/apps/job-launcher/server/package.json
index 599e215cd3..875d27aa6f 100644
--- a/packages/apps/job-launcher/server/package.json
+++ b/packages/apps/job-launcher/server/package.json
@@ -36,6 +36,7 @@
"@nestjs/core": "^10.3.10",
"@nestjs/jwt": "^10.2.0",
"@nestjs/passport": "^10.0.0",
+ "@nestjs/platform-express": "^10.3.10",
"@nestjs/schedule": "^4.0.1",
"@nestjs/serve-static": "^4.0.1",
"@nestjs/swagger": "^7.4.2",
@@ -43,10 +44,14 @@
"@nestjs/typeorm": "^10.0.1",
"@sendgrid/mail": "^8.1.3",
"@types/passport-jwt": "^4.0.1",
+ "@types/uuid": "^10.0.0",
"async-mutex": "^0.5.0",
"bcrypt": "^5.1.1",
+ "body-parser": "^1.20.3",
"class-transformer": "^0.5.1",
+ "class-validator": "^0.14.1",
"decimal.js": "^10.4.3",
+ "helmet": "^7.1.0",
"joi": "^17.13.3",
"json-stable-stringify": "^1.1.1",
"nestjs-minio-client": "^2.2.0",
diff --git a/packages/apps/job-launcher/server/src/modules/job/job.repository.ts b/packages/apps/job-launcher/server/src/modules/job/job.repository.ts
index 162445c015..c054f14d56 100644
--- a/packages/apps/job-launcher/server/src/modules/job/job.repository.ts
+++ b/packages/apps/job-launcher/server/src/modules/job/job.repository.ts
@@ -170,9 +170,9 @@ export class JobRepository extends BaseRepository {
const result = await queryBuilder.getRawOne();
return {
- average: parseFloat(result.average),
- maximum: parseFloat(result.maximum),
- minimum: parseFloat(result.minimum),
+ average: parseFloat(result.average) || 0,
+ maximum: parseFloat(result.maximum) || 0,
+ minimum: parseFloat(result.minimum) || 0,
};
}
@@ -199,11 +199,11 @@ export class JobRepository extends BaseRepository {
const result = await queryBuilder.getRawOne();
return {
- totalJobs: parseInt(result.totalJobs, 10),
- launched: parseInt(result.totalJobs, 10),
- partial: parseInt(result.partial, 10),
- completed: parseInt(result.completed, 10),
- canceled: parseInt(result.canceled, 10),
+ totalJobs: parseInt(result.totalJobs, 10) || 0,
+ launched: parseInt(result.totalJobs, 10) || 0,
+ partial: parseInt(result.partial, 10) || 0,
+ completed: parseInt(result.completed, 10) || 0,
+ canceled: parseInt(result.canceled, 10) || 0,
};
}
diff --git a/packages/apps/job-launcher/server/test/e2e/env-setup.ts b/packages/apps/job-launcher/server/test/e2e/env-setup.ts
index f9c9ee98bf..8dec352553 100644
--- a/packages/apps/job-launcher/server/test/e2e/env-setup.ts
+++ b/packages/apps/job-launcher/server/test/e2e/env-setup.ts
@@ -59,9 +59,6 @@ t86lkzfAep9bfBxbaCBbUhJ1s9+9eeLMG/nUMAaGxWeOwJ92L/KvzN6RFw==
process.env.S3_BUCKET = 'bucket';
process.env.S3_USE_SSL = 'false';
- process.env.MINIO_ROOT_USER = 'access-key';
- process.env.MINIO_ROOT_PASSWORD = 'secrets-key';
-
process.env.STRIPE_API_VERSION = '2022-11-15';
process.env.STRIPE_APP_NAME = 'Staging Launcher Server';
process.env.STRIPE_APP_VERSION = '1.0.0';
@@ -69,6 +66,4 @@ t86lkzfAep9bfBxbaCBbUhJ1s9+9eeLMG/nUMAaGxWeOwJ92L/KvzN6RFw==
'https://github.com/humanprotocol/human-protocol/tree/main/packages/apps/job-launcher/server';
process.env.SENDGRID_API_KEY = 'sendgrid-disabled';
-
- process.env.CRON_SECRET = 'test';
}
diff --git a/packages/apps/reputation-oracle/server/.dockerignore b/packages/apps/reputation-oracle/server/.dockerignore
deleted file mode 100644
index aa3a93b8dd..0000000000
--- a/packages/apps/reputation-oracle/server/.dockerignore
+++ /dev/null
@@ -1,5 +0,0 @@
-Dockerfile
-.dockerignore
-node_modules
-npm-debug.log
-dist
diff --git a/packages/apps/reputation-oracle/server/Dockerfile b/packages/apps/reputation-oracle/server/Dockerfile
index e1c1bf2423..8e81ef1787 100644
--- a/packages/apps/reputation-oracle/server/Dockerfile
+++ b/packages/apps/reputation-oracle/server/Dockerfile
@@ -1,17 +1,27 @@
-# Base image
-FROM node:18
+FROM node:18-slim
+ARG APP_PATH=packages/apps/reputation-oracle/server
# Create app directory
WORKDIR /usr/src/app
-# Bundle app source
-COPY . .
+# Copy expected yarn dist
+COPY .yarn ./.yarn
+COPY .yarnrc ./
+# Copy files for deps installation
+COPY package.json yarn.lock ./
+COPY ${APP_PATH}/package.json ./${APP_PATH}/package.json
+# Some deps are referenced as "*", so we need to build them
+COPY tsconfig.json ./
+COPY packages/core ./packages/core
+COPY packages/sdk ./packages/sdk
-# Install app dependencies
RUN yarn install
-# Creates a "dist" folder with the production build
-RUN yarn workspace @human-protocol/reputation-oracle build
+# Copy everything else to ensure proper build process
+COPY . .
+
+WORKDIR ./${APP_PATH}
+RUN yarn build
-# Start the server using the production build
-CMD [ "node", "packages/apps/reputation-oracle/server/dist/src/main.js" ]
+# Start the server using the build
+CMD [ "yarn", "start:prod" ]
\ No newline at end of file
diff --git a/packages/apps/reputation-oracle/server/package.json b/packages/apps/reputation-oracle/server/package.json
index c236638728..3a246b25c5 100644
--- a/packages/apps/reputation-oracle/server/package.json
+++ b/packages/apps/reputation-oracle/server/package.json
@@ -38,18 +38,26 @@
"@nestjs/core": "^10.3.10",
"@nestjs/jwt": "^10.2.0",
"@nestjs/passport": "^10.0.0",
+ "@nestjs/platform-express": "^10.3.10",
"@nestjs/schedule": "^4.0.1",
+ "@nestjs/serve-static": "^4.0.2",
"@nestjs/swagger": "^7.4.2",
"@nestjs/terminus": "^10.2.1",
"@nestjs/typeorm": "^10.0.1",
+ "@sendgrid/mail": "^8.1.3",
+ "@types/json-stable-stringify": "^1.0.36",
"@types/passport-jwt": "^4.0.1",
"bcrypt": "^5.1.1",
+ "body-parser": "^1.20.3",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
+ "dotenv": "^16.3.2",
+ "ethers": "^6.13.1",
"helmet": "^7.1.0",
"joi": "^17.13.3",
+ "json-stable-stringify": "^1.1.1",
"lodash": "^4.17.21",
- "nestjs-minio-client": "^2.2.0",
+ "minio": "7.1.3",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"pg": "8.13.1",
@@ -67,6 +75,8 @@
"@types/bcrypt": "^5.0.2",
"@types/express": "^4.17.13",
"@types/jest": "29.5.12",
+ "@types/json-stable-stringify": "^1.0.36",
+ "@types/lodash": "^4.17.14",
"@types/node": "22.10.5",
"@types/supertest": "^6.0.2",
"@types/uuid": "^10.0.0",
diff --git a/packages/apps/reputation-oracle/server/scripts/setup-kv-store.ts b/packages/apps/reputation-oracle/server/scripts/setup-kv-store.ts
new file mode 100644
index 0000000000..cd51e5822d
--- /dev/null
+++ b/packages/apps/reputation-oracle/server/scripts/setup-kv-store.ts
@@ -0,0 +1,165 @@
+import 'dotenv/config';
+import { KVStoreClient, KVStoreKeys, Role } from '@human-protocol/sdk';
+import { Wallet, ethers } from 'ethers';
+import * as Minio from 'minio';
+
+async function setupCommonValues(kvStoreClient: KVStoreClient): Promise {
+ const { SUPPORTED_JOB_TYPES = '', SERVER_URL = '', FEE = '' } = process.env;
+
+ if (!SUPPORTED_JOB_TYPES || SUPPORTED_JOB_TYPES.split(',').length === 0) {
+ throw new Error('SUPPORTED_JOB_TYPES should be comma-separated list');
+ }
+ try {
+ new URL(SERVER_URL || '');
+ } catch (noop) {
+ throw new Error('Invalid SERVER_URL');
+ }
+ let url = SERVER_URL.endsWith('/') ? SERVER_URL.slice(0, -1) : SERVER_URL;
+ if (!url.startsWith('http')) {
+ url = `http://${url}`;
+ }
+
+ const fee = Number(FEE);
+ if (!Number.isInteger(fee) || fee < 1) {
+ throw new Error('Fee must be positive integer');
+ }
+
+ await kvStoreClient.setBulk(
+ [
+ KVStoreKeys.role,
+ KVStoreKeys.fee,
+ KVStoreKeys.url,
+ KVStoreKeys.webhookUrl,
+ KVStoreKeys.jobTypes,
+ ],
+ [
+ Role.ReputationOracle,
+ `${fee}`,
+ url,
+ `${url}/webhook`,
+ SUPPORTED_JOB_TYPES,
+ ],
+ );
+}
+
+type SetupPublicKeyFileMeta = {
+ keyName: string;
+ publicKey: string;
+ s3Bucket: string;
+ s3Endpoint: string;
+ s3Port: string;
+ kvKey: string;
+};
+
+async function setupPublicKeyFile(
+ kvStoreClient: KVStoreClient,
+ minioClient: Minio.Client,
+ meta: SetupPublicKeyFileMeta,
+): Promise {
+ const { keyName, kvKey, publicKey, s3Bucket, s3Endpoint, s3Port } = meta;
+ const exists = await minioClient.bucketExists(s3Bucket);
+ if (!exists) {
+ throw new Error('Bucket does not exists');
+ }
+
+ await minioClient.putObject(s3Bucket, keyName, publicKey, {
+ 'Content-Type': 'text/plain',
+ 'Cache-Control': 'no-store',
+ });
+ /**
+ * Protocol is required for 'setFileUrlAndHash'
+ */
+ const _s3Endpoint = s3Endpoint.startsWith('http')
+ ? s3Endpoint
+ : `http://${s3Endpoint}`;
+ const fileUrl = `${_s3Endpoint}:${s3Port}/${s3Bucket}/${keyName}`;
+ await kvStoreClient.setFileUrlAndHash(fileUrl, kvKey);
+}
+
+async function setup(): Promise {
+ const { WEB3_PRIVATE_KEY, RPC_URL } = process.env;
+ if (!WEB3_PRIVATE_KEY) {
+ throw new Error('Private key is empty');
+ }
+ if (!RPC_URL) {
+ throw new Error('RPC url is empty');
+ }
+
+ const provider = new ethers.JsonRpcProvider(RPC_URL);
+ const wallet = new Wallet(WEB3_PRIVATE_KEY, provider);
+
+ const kvStoreClient = await KVStoreClient.build(wallet);
+
+ await setupCommonValues(kvStoreClient);
+
+ const {
+ S3_ENDPOINT,
+ S3_PORT,
+ S3_USE_SSL,
+ S3_ACCESS_KEY,
+ S3_SECRET_KEY,
+ S3_BUCKET,
+ } = process.env;
+
+ if (
+ [S3_ENDPOINT, S3_PORT, S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET].some(
+ (value) => !value,
+ )
+ ) {
+ throw new Error('Missing S3 config value');
+ }
+ if (!S3_ACCESS_KEY || !S3_SECRET_KEY) {
+ throw new Error('S3 key is missing');
+ }
+ if (!S3_BUCKET) {
+ throw new Error('S3 bucket is missing');
+ }
+
+ const s3Endpoint = S3_ENDPOINT || 'localhost';
+ const s3Port = S3_PORT || '9000';
+ const minioClient = new Minio.Client({
+ endPoint: s3Endpoint,
+ port: parseInt(s3Port, 10),
+ useSSL: S3_USE_SSL === 'true',
+ accessKey: S3_ACCESS_KEY,
+ secretKey: S3_SECRET_KEY,
+ });
+
+ const { PGP_ENCRYPT, PGP_PUBLIC_KEY } = process.env;
+ if (PGP_ENCRYPT && PGP_ENCRYPT === 'true') {
+ if (!PGP_PUBLIC_KEY) {
+ throw new Error('PGP public key is empty');
+ }
+ await setupPublicKeyFile(kvStoreClient, minioClient, {
+ s3Endpoint,
+ s3Port,
+ s3Bucket: S3_BUCKET,
+ publicKey: PGP_PUBLIC_KEY,
+ keyName: 'pgp-public-key',
+ kvKey: KVStoreKeys.publicKey,
+ });
+ }
+
+ const { JWT_PUBLIC_KEY } = process.env;
+ if (!JWT_PUBLIC_KEY) {
+ throw new Error('JWT_PUBLIC_KEY is missing');
+ }
+ await setupPublicKeyFile(kvStoreClient, minioClient, {
+ s3Endpoint,
+ s3Port,
+ s3Bucket: S3_BUCKET,
+ publicKey: JWT_PUBLIC_KEY,
+ keyName: 'jwt-public-key',
+ kvKey: 'jwt_public_key',
+ });
+}
+
+(async () => {
+ try {
+ await setup();
+ process.exit(0);
+ } catch (error) {
+ console.error('Failed to setup KV', error);
+ process.exit(1);
+ }
+})();
diff --git a/packages/examples/cvat/recording-oracle/src/core/config.py b/packages/examples/cvat/recording-oracle/src/core/config.py
index 11b9c6e8bf..fa262b8b0b 100644
--- a/packages/examples/cvat/recording-oracle/src/core/config.py
+++ b/packages/examples/cvat/recording-oracle/src/core/config.py
@@ -104,6 +104,7 @@ class IStorageConfig:
data_bucket_name: ClassVar[str]
secure: ClassVar[bool]
endpoint_url: ClassVar[str] # TODO: probably should be optional
+ use_path_style: ClassVar[bool]
# AWS S3 specific attributes
access_key: ClassVar[str | None]
secret_key: ClassVar[str | None]
@@ -120,7 +121,7 @@ def provider_endpoint_url(cls) -> str:
@classmethod
def bucket_url(cls) -> str:
- if is_ipv4(cls.endpoint_url):
+ if is_ipv4(cls.endpoint_url) or cls.use_path_style:
return f"{cls.get_scheme()}{cls.endpoint_url}/{cls.data_bucket_name}/"
return f"{cls.get_scheme()}{cls.data_bucket_name}.{cls.endpoint_url}/"
@@ -130,6 +131,7 @@ class StorageConfig(IStorageConfig):
endpoint_url = os.environ["STORAGE_ENDPOINT_URL"] # TODO: probably should be optional
data_bucket_name = os.environ["STORAGE_RESULTS_BUCKET_NAME"]
secure = to_bool(getenv("STORAGE_USE_SSL", "true"))
+ use_path_style = to_bool(getenv("STORAGE_USE_PATH_STYLE", "false"))
# AWS S3 specific attributes
access_key = getenv("STORAGE_ACCESS_KEY")
@@ -148,6 +150,7 @@ class ExchangeOracleStorageConfig(IStorageConfig):
data_bucket_name = os.environ["EXCHANGE_ORACLE_STORAGE_RESULTS_BUCKET_NAME"]
results_dir_suffix = getenv("STORAGE_RESULTS_DIR_SUFFIX", "-results")
secure = to_bool(getenv("EXCHANGE_ORACLE_STORAGE_USE_SSL", "true"))
+ use_path_style = to_bool(getenv("EXCHANGE_ORACLE_STORAGE_USE_PATH_STYLE", "false"))
# AWS S3 specific attributes
access_key = getenv("EXCHANGE_ORACLE_STORAGE_ACCESS_KEY")
secret_key = getenv("EXCHANGE_ORACLE_STORAGE_SECRET_KEY")
diff --git a/scripts/cvat/Makefile b/scripts/cvat/Makefile
new file mode 100644
index 0000000000..03ca3c11fe
--- /dev/null
+++ b/scripts/cvat/Makefile
@@ -0,0 +1,18 @@
+.PHONY: copy-env-files
+
+copy-env-files:
+# Copying .env file for compose itself
+ @cp ./env-files/.env.compose .env.compose.local
+# Copying .env files for backend services
+ @cp ./env-files/.env.reputation-oracle ./.env.reputation-oracle.local
+ @cp ./env-files/.env.human-app-server .env.human-app-server.local
+ @cp ./env-files/.env.job-launcher ./.env.job-launcher.local
+ @cp ./env-files/.env.exchange-oracle ./.env.exchange-oracle.local
+ @cp ./env-files/.env.recording-oracle ./.env.recording-oracle.local
+# Copying .env files for client apps.
+# It should be placed in corresponding app folder
+# because used during Docker image build process
+ @cp ./env-files/.env.human-app-client ../../packages/apps/human-app/frontend/.env.local
+ @cp ./env-files/.env.job-launcher-client ../../packages/apps/job-launcher/client/.env.local
+# Restore original files
+ @git checkout . > /dev/null 2>&1
\ No newline at end of file
diff --git a/scripts/cvat/docker-compose.local.yml b/scripts/cvat/docker-compose.local.yml
new file mode 100644
index 0000000000..14ccd6e9bd
--- /dev/null
+++ b/scripts/cvat/docker-compose.local.yml
@@ -0,0 +1,493 @@
+name: human-protocol-local-setup
+
+x-service-default-config:
+ restart: &default-restart unless-stopped
+ logging: &default-logging
+ options:
+ max-size: 10m
+ max-file: 3
+
+x-hardcoded-vars:
+ frontend_default_port: &frontend_default_port 3000
+ all_interfaces_ip: &all_interfaces_ip '0.0.0.0'
+ web3_env: &web3_env testnet
+ postgres_host: &postgres_host postgres
+ postgres_port: &postgres_port 5432
+ redis_host: &redis_host redis
+ redis_port: &redis_port 6379
+ minio_host: &minio_host minio
+ node_env: &node_env local
+ cvat_lb_url: &cvat_lb_url 'http://cvat-lb:8080'
+ cvat_oracle_storage_provider: &cvat_oracle_storage_provider aws
+
+x-general-env-variables:
+ # GENERAL VARS
+ subgraph_api_key: &subgraph_api_key ${SUBGRAPH_API_KEY}
+ sendgrid_api_key: &sendgrid_api_key ${SENDGRID_API_KEY:-sendgrid-disabled}
+ rpc_url_polygon_amoy: &rpc_url_polygon_amoy ${RPC_URL_POLYGON_AMOY:-}
+ # POSTGRES VARS
+ postgres_user: &postgres_user ${POSTGRES_USER:-default}
+ postgres_password: &postgres_password ${POSTGRES_PASSWORD:-qwerty}
+ # MINIO VARS
+ minio_port: &minio_port ${MINIO_PORT:?}
+ minio_console_port: &minio_console_port ${MINIO_CONSOLE_PORT:-9001}
+ minio_root_user: &minio_root_user ${MINIO_ROOT_USER:-minioadmin}
+ minio_root_password: &minio_root_password ${MINIO_ROOT_PASSWORD:-minioadmin}
+ minio_services_access_key: &minio_services_access_key ${MINIO_SERVICES_ACCESS_KEY:-human-oracle}
+ minio_services_secret_key: &minio_services_secret_key ${MINIO_SERVICES_SECRET_KEY:-human-oracle-s3-secret}
+ # BUCKET NAMES
+ bucket_name_manifests: &bucket_name_manifests ${BUCKET_NAME_MANIFESTS:-manifests}
+ bucket_name_datasets: &bucket_name_datasets ${BUCKET_NAME_DATASETS:-datasets}
+ bucket_name_rep_o: &bucket_name_rep_o ${BUCKET_NAME_REPUTATION_ORACLE:-reputation-oracle}
+ bucket_name_exc_o: &bucket_name_exc_o ${BUCKET_NAME_EXCHANGE_ORACLE:-exchange-oracle}
+ bucket_name_rec_o: &bucket_name_rec_o ${BUCKET_NAME_RECORDING_ORACLE:-recording-oracle}
+ # WEB3 ADDRESSES
+ reputation_oracle_address: &reputation_oracle_address ${REPUTATION_ORACLE_ADDRESS:?}
+ exchange_oracle_address: &exchange_oracle_address ${EXCHANGE_ORACLE_ADDRESS:?}
+ recording_oracle_address: &recording_oracle_address ${RECORDING_ORACLE_ADDRESS:?}
+ # OTHER
+ backend_apps_internal_port: &backend_apps_internal_port ${BACKEND_APPS_INTERNAL_PORT:?}
+ human_app_email: &human_app_email ${HUMAN_APP_EMAIL:?}
+ reputation_oracle_jwt_public_key: &reputation_oracle_jwt_public_key ${REPUTATION_ORACLE_JWT_PUBLIC_KEY:?}
+ cvat_oracle_storage_endpoint: &cvat_oracle_storage_endpoint minio:${MINIO_PORT:?}
+
+x-service-env-vars-groups:
+ postgres_auth_vars: &postgres_auth_vars
+ POSTGRES_USER: *postgres_user
+ POSTGRES_PASSWORD: *postgres_password
+ redis_app_vars: &redis_app_vars
+ REDIS_HOST: *redis_host
+ REDIS_PORT: *redis_port
+ nodejs_app_vars: &nodejs_app_vars
+ NODE_ENV: *node_env
+ WEB3_ENV: *web3_env
+ RPC_URL_POLYGON_AMOY: *rpc_url_polygon_amoy
+ SENDGRID_API_KEY: *sendgrid_api_key
+ SUBGRAPH_API_KEY: *subgraph_api_key
+ HCAPTCHA_SITE_KEY: ${HCAPTCHA_SITE_KEY:-10000000-ffff-ffff-ffff-000000000001}
+ HCAPTCHA_SECRET: ${HCAPTCHA_SECRET:-0x0000000000000000000000000000000000000000}
+ HCAPTCHA_API_KEY: ${HCAPTCHA_API_KEY:-test}
+ nodejs_app_postgres_vars: &nodejs_app_postgres_vars
+ <<: *postgres_auth_vars
+ POSTGRES_HOST: *postgres_host
+ POSTGRES_PORT: *postgres_port
+ POSTGRES_SSL: 'false'
+ nodejs_app_s3_vars: &nodejs_app_s3_vars
+ S3_ENDPOINT: *minio_host
+ S3_PORT: *minio_port
+ S3_ACCESS_KEY: *minio_services_access_key
+ S3_SECRET_KEY: *minio_services_secret_key
+ S3_USE_SSL: 'false'
+ cvat_oracle_postgres_vars: &cvat_oracle_postgres_vars
+ PG_HOST: *postgres_host
+ PG_PORT: *postgres_port
+ PG_USER: *postgres_user
+ PG_PASSWORD: *postgres_password
+ cvat_oracle_storage_connection_vars: &cvat_oracle_storage_connection_vars
+ STORAGE_PROVIDER: *cvat_oracle_storage_provider
+ STORAGE_ENDPOINT_URL: *cvat_oracle_storage_endpoint
+ STORAGE_ACCESS_KEY: *minio_services_access_key
+ STORAGE_SECRET_KEY: *minio_services_secret_key
+ STORAGE_USE_SSL: 'false'
+ cvat_connection_vars: &cvat_connection_vars
+ CVAT_URL: *cvat_lb_url
+ CVAT_ADMIN: ${CVAT_ADMIN:-human-protocol}
+ CVAT_ADMIN_PASS: ${CVAT_ADMIN_PASS:-qwe123qwe123Q!}
+ CVAT_ORG_SLUG: HumanAppLocal
+
+services:
+ postgres:
+ container_name: human-postgres
+ image: postgres:16
+ restart: *default-restart
+ logging:
+ <<: *default-logging
+ networks:
+ - human_protocol
+ ports:
+ - name: instance_port
+ target: *postgres_port
+ # default 5432 is used by CVAT installation
+ published: ${POSTGRES_PORT:-5433}
+ volumes:
+ - ./initdb:/docker-entrypoint-initdb.d
+ - postgres-data:/var/lib/postgresql/data
+ environment:
+ <<: *postgres_auth_vars
+ healthcheck:
+ test: ["CMD", "pg_isready"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
+ redis:
+ container_name: human-redis
+ image: redis:6
+ restart: *default-restart
+ logging:
+ <<: *default-logging
+ networks:
+ - human_protocol
+ ports:
+ - name: instance_port
+ target: *redis_port
+ # default 6379 is used by CVAT installation
+ published: ${REDIS_PORT:-6380}
+ volumes:
+ - redis-data:/data
+ command: [
+ "redis-server",
+ # we don not expect a lot of writes on local
+ "--save", "60", "100",
+ "--appendonly", "yes",
+ ]
+
+ minio:
+ container_name: human-minio
+ image: minio/minio:RELEASE.2024-12-18T13-15-44Z
+ restart: *default-restart
+ logging:
+ <<: *default-logging
+ entrypoint: 'sh'
+ networks:
+ - human_protocol
+ - human_cvat_bridge
+ ports:
+ - name: instance_port
+ target: 9000
+ published: *minio_port
+ - name: console_port
+ target: 9001
+ published: *minio_console_port
+ volumes:
+ - minio-data:/data
+ environment:
+ MINIO_ROOT_USER: *minio_root_user
+ MINIO_ROOT_PASSWORD: *minio_root_password
+ command:
+ -c "minio server /data --console-address ':9001'"
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
+ interval: 5s
+ timeout: 5s
+ retries: 3
+
+ minio-client:
+ container_name: human-minio-client
+ image: minio/mc:RELEASE.2024-11-21T17-21-54Z
+ depends_on:
+ minio:
+ condition: service_healthy
+ networks:
+ - human_protocol
+ environment:
+ MINIO_ROOT_USER: *minio_root_user
+ MINIO_ROOT_PASSWORD: *minio_root_password
+ SERVICES_ACCESS_KEY: *minio_services_access_key
+ SERVICES_SECRET_KEY: *minio_services_secret_key
+ BUCKET_MANIFESTS: *bucket_name_manifests
+ BUCKET_DATASETS: *bucket_name_datasets
+ BUCKET_REPUTATION_ORACLE: *bucket_name_rep_o
+ BUCKET_EXCHANGE_ORACLE: *bucket_name_exc_o
+ BUCKET_RECORDING_ORACLE: *bucket_name_rec_o
+ entrypoint: >
+ /bin/sh -c "
+ mc alias set myminio http://minio:9000 $$MINIO_ROOT_USER $$MINIO_ROOT_PASSWORD
+
+ mc admin user add myminio $$SERVICES_ACCESS_KEY $$SERVICES_SECRET_KEY
+ mc admin policy attach myminio readwrite --user=$$SERVICES_ACCESS_KEY
+
+ mc mb myminio/$$BUCKET_MANIFESTS;
+ mc anonymous set public myminio/$$BUCKET_MANIFESTS;
+
+ mc mb myminio/$$BUCKET_DATASETS;
+ mc anonymous set public myminio/$$BUCKET_DATASETS;
+
+ mc mb myminio/$$BUCKET_REPUTATION_ORACLE;
+ mc anonymous set public myminio/$$BUCKET_REPUTATION_ORACLE;
+
+ mc mb myminio/$$BUCKET_EXCHANGE_ORACLE;
+ mc anonymous set public myminio/$$BUCKET_EXCHANGE_ORACLE;
+
+ mc mb myminio/$$BUCKET_RECORDING_ORACLE;
+ mc anonymous set public myminio/$$BUCKET_RECORDING_ORACLE;
+ "
+
+ reputation-oracle:
+ container_name: reputation-oracle
+ image: human-protocol/reputation-oracle
+ pull_policy: build
+ depends_on:
+ postgres:
+ condition: service_healthy
+ minio:
+ condition: service_healthy
+ minio-client:
+ condition: service_completed_successfully
+ restart: *default-restart
+ logging:
+ <<: *default-logging
+ build:
+ context: ../../
+ dockerfile: packages/apps/reputation-oracle/server/Dockerfile
+ expose:
+ - *backend_apps_internal_port
+ networks:
+ - human_protocol
+ ports:
+ - name: server_port
+ target: *backend_apps_internal_port
+ published: ${REPUTATION_ORACLE_PORT:-5001}
+ env_file: ./.env.reputation-oracle.local
+ environment:
+ <<: [*nodejs_app_vars, *nodejs_app_postgres_vars, *nodejs_app_s3_vars]
+ HOST: *all_interfaces_ip
+ PORT: *backend_apps_internal_port
+ POSTGRES_DATABASE: reputation-oracle
+ S3_BUCKET: *bucket_name_rep_o
+ KYC_API_PRIVATE_KEY: ${KYC_API_PRIVATE_KEY:-none}
+ HUMAN_APP_EMAIL: *human_app_email
+ # It is accessed by user, not from container
+ # so put here exposed port, not internal
+ FE_URL: http://localhost:${HUMAN_APP_CLIENT_PORT:?}
+ JWT_PUBLIC_KEY: *reputation_oracle_jwt_public_key
+
+ human-app-server:
+ container_name: human-app-server
+ image: human-protocol/human-app-server
+ pull_policy: build
+ depends_on:
+ redis:
+ condition: service_started
+ restart: *default-restart
+ logging:
+ <<: *default-logging
+ build:
+ context: ../../
+ dockerfile: packages/apps/human-app/server/Dockerfile
+ expose:
+ - *backend_apps_internal_port
+ networks:
+ - human_protocol
+ ports:
+ - name: server_port
+ target: *backend_apps_internal_port
+ published: ${HUMAN_APP_SERVER_PORT:-5002}
+ env_file: ./.env.human-app-server.local
+ environment:
+ <<: [*nodejs_app_vars, *redis_app_vars]
+ HOST: *all_interfaces_ip
+ PORT: *backend_apps_internal_port
+ REDIS_DB: 1
+ RPC_URL: *rpc_url_polygon_amoy
+ HUMAN_APP_EMAIL: *human_app_email
+ REPUTATION_ORACLE_URL: "http://reputation-oracle:${BACKEND_APPS_INTERNAL_PORT:?}"
+ REPUTATION_ORACLE_ADDRESS: *reputation_oracle_address
+
+ human-app-client:
+ container_name: human-app-client
+ image: human-protocol/human-app-client
+ pull_policy: build
+ depends_on:
+ human-app-server:
+ condition: service_started
+ restart: *default-restart
+ logging:
+ <<: *default-logging
+ build:
+ context: ../../
+ dockerfile: packages/apps/human-app/frontend/Dockerfile
+ expose:
+ - *frontend_default_port
+ networks:
+ - human_protocol
+ ports:
+ - name: server_port
+ target: *frontend_default_port
+ published: ${HUMAN_APP_CLIENT_PORT:?}
+ environment:
+ PORT: *frontend_default_port
+
+ exchange-oracle:
+ container_name: exchange-oracle-cvat
+ image: human-protocol/exchange-oracle-cvat
+ pull_policy: build
+ depends_on:
+ postgres:
+ condition: service_healthy
+ minio:
+ condition: service_healthy
+ minio-client:
+ condition: service_completed_successfully
+ redis:
+ condition: service_started
+ restart: *default-restart
+ logging:
+ <<: *default-logging
+ build:
+ context: ../../packages/examples/cvat/exchange-oracle
+ dockerfile: ./Dockerfile
+ expose:
+ - *backend_apps_internal_port
+ networks:
+ human_protocol:
+ human_cvat_bridge:
+ aliases:
+ - exchange-oracle.app
+ ports:
+ - name: server_port
+ target: *backend_apps_internal_port
+ published: ${EXCHANGE_ORACLE_PORT:-5003}
+ env_file: ./.env.exchange-oracle.local
+ environment:
+ HOST: *all_interfaces_ip
+ PORT: *backend_apps_internal_port
+ <<: [
+ *cvat_oracle_postgres_vars,
+ *redis_app_vars,
+ *cvat_oracle_storage_connection_vars,
+ *cvat_connection_vars
+ ]
+ REDIS_DB: 2
+ PG_DB: exchange-oracle
+ POLYGON_AMOY_RPC_API_URL: *rpc_url_polygon_amoy
+ POLYGON_AMOY_ADDR: *exchange_oracle_address
+ STORAGE_BUCKET_NAME: *bucket_name_exc_o
+ HUMAN_APP_JWT_KEY: *reputation_oracle_jwt_public_key
+ CVAT_INCOMING_WEBHOOKS_URL: "http://exchange-oracle.app:${BACKEND_APPS_INTERNAL_PORT:?}/cvat-webhook"
+ LOCALHOST_RECORDING_ORACLE_URL: "http://recording-oracle:${BACKEND_APPS_INTERNAL_PORT:?}/webhook"
+ LOCALHOST_JOB_LAUNCHER_URL: "http://job-launcher:${BACKEND_APPS_INTERNAL_PORT:?}/webhook"
+ LOCALHOST_RECORDING_ORACLE_ADDRESS: *recording_oracle_address
+
+ recording-oracle:
+ container_name: recording-oracle-cvat
+ image: human-protocol/recording-oracle-cvat
+ pull_policy: build
+ depends_on:
+ postgres:
+ condition: service_healthy
+ minio:
+ condition: service_healthy
+ minio-client:
+ condition: service_completed_successfully
+ restart: *default-restart
+ logging:
+ <<: *default-logging
+ build:
+ context: ../../packages/examples/cvat/recording-oracle
+ dockerfile: ./Dockerfile
+ expose:
+ - *backend_apps_internal_port
+ networks:
+ - human_protocol
+ - human_cvat_bridge
+ ports:
+ - name: server_port
+ target: *backend_apps_internal_port
+ published: ${RECORDING_ORACLE_PORT:-5004}
+ env_file: ./.env.recording-oracle.local
+ environment:
+ HOST: *all_interfaces_ip
+ PORT: *backend_apps_internal_port
+ <<: [
+ *cvat_oracle_postgres_vars,
+ *cvat_oracle_storage_connection_vars,
+ *cvat_connection_vars
+ ]
+ PG_DB: recording-oracle
+ POLYGON_AMOY_RPC_API_URL: *rpc_url_polygon_amoy
+ POLYGON_AMOY_ADDR: *recording_oracle_address
+ STORAGE_RESULTS_BUCKET_NAME: *bucket_name_rec_o
+ STORAGE_USE_PATH_STYLE: "true"
+ EXCHANGE_ORACLE_STORAGE_PROVIDER: *cvat_oracle_storage_provider
+ EXCHANGE_ORACLE_STORAGE_ENDPOINT_URL: *cvat_oracle_storage_endpoint
+ EXCHANGE_ORACLE_STORAGE_ACCESS_KEY: *minio_services_access_key
+ EXCHANGE_ORACLE_STORAGE_SECRET_KEY: *minio_services_secret_key
+ EXCHANGE_ORACLE_STORAGE_RESULTS_BUCKET_NAME: *bucket_name_exc_o
+ EXCHANGE_ORACLE_STORAGE_USE_SSL: 'false'
+ LOCALHOST_EXCHANGE_ORACLE_URL: "http://exchange-oracle:${BACKEND_APPS_INTERNAL_PORT:?}/webhook"
+ LOCALHOST_REPUTATION_ORACLE_URL: "http://reputation-oracle:${BACKEND_APPS_INTERNAL_PORT:?}/webhook"
+ LOCALHOST_EXCHANGE_ORACLE_ADDRESS: *exchange_oracle_address
+
+ job-launcher:
+ container_name: job-launcher
+ image: human-protocol/job-launcher
+ pull_policy: build
+ depends_on:
+ postgres:
+ condition: service_healthy
+ minio:
+ condition: service_healthy
+ minio-client:
+ condition: service_completed_successfully
+ restart: *default-restart
+ logging:
+ <<: *default-logging
+ build:
+ context: ../../
+ dockerfile: packages/apps/job-launcher/server/Dockerfile
+ expose:
+ - *backend_apps_internal_port
+ networks:
+ - human_protocol
+ ports:
+ - name: server_port
+ target: *backend_apps_internal_port
+ published: ${JOB_LAUNCHER_PORT:-5005}
+ env_file: ./.env.job-launcher.local
+ environment:
+ <<: [*nodejs_app_vars, *nodejs_app_postgres_vars, *nodejs_app_s3_vars]
+ HOST: *all_interfaces_ip
+ PORT: *backend_apps_internal_port
+ POSTGRES_DATABASE: job-launcher
+ S3_BUCKET: *bucket_name_manifests
+ REPUTATION_ORACLES: *exchange_oracle_address
+ CVAT_EXCHANGE_ORACLE_ADDRESS: *exchange_oracle_address
+ CVAT_RECORDING_ORACLE_ADDRESS: *recording_oracle_address
+ REPUTATION_ORACLE_ADDRESS: *reputation_oracle_address
+ FE_URL: http://localhost:${JOB_LAUNCHER_CLIENT_PORT:?}
+
+ job-launcher-client:
+ container_name: job-launcher-client
+ image: human-protocol/job-launcher-client
+ pull_policy: build
+ depends_on:
+ job-launcher:
+ condition: service_started
+ restart: *default-restart
+ logging:
+ <<: *default-logging
+ build:
+ context: ../../
+ dockerfile: packages/apps/job-launcher/client/Dockerfile
+ expose:
+ - *frontend_default_port
+ networks:
+ - human_protocol
+ ports:
+ - name: server_port
+ target: *frontend_default_port
+ published: ${JOB_LAUNCHER_CLIENT_PORT:?}
+ environment:
+ PORT: *frontend_default_port
+
+volumes:
+ # When init for the first time postgres requires empty directory
+ # that is exclusive to its user, so providing a separate volume
+ postgres-data:
+ redis-data:
+ minio-data:
+
+networks:
+ human_protocol:
+ name: human-protocol
+ # CVAT oracles since they need to access CVAT
+ human_cvat_bridge:
+ name: human-cvat-bridge
+ driver: bridge
+ driver_opts:
+ # Default is also 'true'
+ com.docker.network.bridge.enable_icc: 'true'
+ # Default is also 'true'
+ com.docker.network.bridge.enable_ip_masquerade: 'true'
+ com.docker.network.driver.mtu: 1500
diff --git a/scripts/cvat/env-files/.env.compose b/scripts/cvat/env-files/.env.compose
new file mode 100644
index 0000000000..9a307825f1
--- /dev/null
+++ b/scripts/cvat/env-files/.env.compose
@@ -0,0 +1,21 @@
+MINIO_PORT=9000
+
+BACKEND_APPS_INTERNAL_PORT=5000
+REPUTATION_ORACLE_EXPOSED_PORT=5001
+HUMAN_APP_CLIENT_PORT=3001
+JOB_LAUNCHER_CLIENT_PORT=3002
+
+HUMAN_APP_EMAIL=human-app@local.app
+REPUTATION_ORACLE_JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkPekD3q96LHt4IfvY1UY1YukTeEf
+K+XryPXhU57nKuhZXBPRrQ+lMDeFpYpHWpGqA/K576n+rDvjbBgHfQiHKg==
+-----END PUBLIC KEY-----"
+
+RPC_URL_POLYGON_AMOY=https://rpc-amoy.polygon.technology
+# Oracle addresses
+REPUTATION_ORACLE_ADDRESS=replace_me
+EXCHANGE_ORACLE_ADDRESS=replace_me
+RECORDING_ORACLE_ADDRESS=replace_me
+
+# Might be empty
+SUBGRAPH_API_KEY=
diff --git a/scripts/cvat/env-files/.env.exchange-oracle b/scripts/cvat/env-files/.env.exchange-oracle
new file mode 100644
index 0000000000..6ee37a5497
--- /dev/null
+++ b/scripts/cvat/env-files/.env.exchange-oracle
@@ -0,0 +1,57 @@
+## Polygon Amoy Config
+POLYGON_AMOY_PRIVATE_KEY=replace_me
+
+## Cron Config
+## To make environment more convenient with faster updates
+PROCESS_JOB_LAUNCHER_WEBHOOKS_INT=10
+PROCESS_RECORDING_ORACLE_WEBHOOKS_INT=10
+TRACK_COMPLETED_PROJECTS_INT=10
+TRACK_COMPLETED_TASKS_INT=10
+TRACK_COMPLETED_ESCROWS_INT=10
+TRACK_CREATING_TASKS_INT=10
+TRACK_ASSIGNMENTS_INT=10
+TRACK_ESCROW_CREATION_INT=100
+
+## Features
+ENABLE_CUSTOM_CLOUD_HOST="yes"
+REQUEST_LOGGING_ENABLED="yes"
+PROFILING_ENABLED="yes"
+
+## Core
+DEFAULT_ASSIGNMENT_TIME=600
+
+## PGP Keys data
+PGP_PRIVATE_KEY="-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xYYEZ4+2FxYJKwYBBAHaRw8BAQdAodfgvZwd1/s2tStzumk9T+WhuirhI8AD
+eEOG4jdMhdD+CQMI9hA7Uf00eCXgAmMXD7ffmZaIpOjJXd3I4GM8mvKqP2DV
+Ts6iDtfTy0f/jqEdTgNoh9Q5Q6uXW3/zAXivDtc7hGaMMA6/ITQsk7tg7LtL
+HM0rRXhjaGFuZ2UgT3JhY2xlIDxleGNoYW5nZS1vcmFjbGVAbG9jYWwuYXBw
+PsKMBBAWCgA+BYJnj7YXBAsJBwgJkNHy48FpPLsnAxUICgQWAAIBAhkBApsD
+Ah4BFiEEydMT95OC9OCzQFjL0fLjwWk8uycAALavAP9RKP8wUxhuFKxFQ7IB
+SQTTAZgamwezk0KqEuy6U70UtwEAiWyjFo3Y5oTzaOABs3YTogumq3v+Kmnn
+yYNl/UHyZwXHiwRnj7YXEgorBgEEAZdVAQUBAQdA0THKoGl7/bviCOOm0MZ2
+6CSyN/PbPL5j9C6m5T/90GcDAQgH/gkDCBJs91BQdiVL4PZj8WlKnyu+7sBD
+p1pKRAqCxx/DDnYWGTFyW8JMgM6bcEfCIl+q5WeO35k1SXFJKUu2Wd1Cl5r1
+kp/DonyJmiRM+Lo/evbCeAQYFgoAKgWCZ4+2FwmQ0fLjwWk8uycCmwwWIQTJ
+0xP3k4L04LNAWMvR8uPBaTy7JwAAVCEBAKBllZtzefLZsoE0behnwu5SCnSS
+ORb+9kItQJMdBcnWAP9HcsCq3Ve6pOUXBuMWlmQ8IspXQ/oPHdQ7gEJ8+q6H
+Bw==
+=w1I+
+-----END PGP PRIVATE KEY BLOCK-----"
+PGP_PASSPHRASE=exc-o-pgp-password
+PGP_PUBLIC_KEY="-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+xjMEZ4+2FxYJKwYBBAHaRw8BAQdAodfgvZwd1/s2tStzumk9T+WhuirhI8AD
+eEOG4jdMhdDNK0V4Y2hhbmdlIE9yYWNsZSA8ZXhjaGFuZ2Utb3JhY2xlQGxv
+Y2FsLmFwcD7CjAQQFgoAPgWCZ4+2FwQLCQcICZDR8uPBaTy7JwMVCAoEFgAC
+AQIZAQKbAwIeARYhBMnTE/eTgvTgs0BYy9Hy48FpPLsnAAC2rwD/USj/MFMY
+bhSsRUOyAUkE0wGYGpsHs5NCqhLsulO9FLcBAIlsoxaN2OaE82jgAbN2E6IL
+pqt7/ipp58mDZf1B8mcFzjgEZ4+2FxIKKwYBBAGXVQEFAQEHQNExyqBpe/27
+4gjjptDGdugksjfz2zy+Y/QupuU//dBnAwEIB8J4BBgWCgAqBYJnj7YXCZDR
+8uPBaTy7JwKbDBYhBMnTE/eTgvTgs0BYy9Hy48FpPLsnAABUIQEAoGWVm3N5
+8tmygTRt6GfC7lIKdJI5Fv72Qi1Akx0FydYA/0dywKrdV7qk5RcG4xaWZDwi
+yldD+g8d1DuAQnz6rocH
+=AVB0
+-----END PGP PUBLIC KEY BLOCK-----"
+PGP_PUBLIC_KEY_URL=http://minio:9000/exchange-oracle/pgp-public-key
diff --git a/scripts/cvat/env-files/.env.human-app-client b/scripts/cvat/env-files/.env.human-app-client
new file mode 100644
index 0000000000..30464f42d5
--- /dev/null
+++ b/scripts/cvat/env-files/.env.human-app-client
@@ -0,0 +1,28 @@
+VITE_API_URL=http://localhost:5002
+VITE_NETWORK=testnet
+# Reown project id
+VITE_WALLET_CONNECT_PROJECT_ID=replace_me
+VITE_DAPP_ICONS=icon1,icon2
+VITE_DAPP_META_DESCRIPTION=Complete jobs, earn HMT
+VITE_DAPP_META_NAME=Human App Local
+VITE_DAPP_META_URL=http://localhost:3001
+# Keep it empty
+VITE_H_CAPTCHA_EXCHANGE_URL=
+# Keep it empty
+VITE_H_CAPTCHA_LABELING_BASE_URL=
+VITE_H_CAPTCHA_SITE_KEY=10000000-ffff-ffff-ffff-000000000001
+VITE_DAILY_SOLVED_CAPTCHA_LIMIT=0
+VITE_HMT_DAILY_SPENT_LIMIT=0
+VITE_HUMAN_PROTOCOL_HELP_URL=https://docs.humanprotocol.org/
+VITE_HUMAN_PROTOCOL_URL=https://humanprotocol.org/
+VITE_HUMAN_SUPPORT_EMAIL=support@local.app
+VITE_NAVBAR__LINK__HOW_IT_WORK_URL=https://humanprotocol.org/
+VITE_NAVBAR__LINK__PROTOCOL_URL=https://humanprotocol.org/
+VITE_PRIVACY_POLICY_URL=http://local.app/privacy-policy/
+VITE_TERMS_OF_SERVICE_URL=http://local.app/terms-and-conditions/
+VITE_H_CAPTCHA_ORACLE_ANNOTATION_TOOL=hcaptcha
+VITE_H_CAPTCHA_ORACLE_ROLE=hcaptcha
+# Keep it empty
+VITE_H_CAPTCHA_ORACLE_ADDRESS=
+VITE_H_CAPTCHA_ORACLE_TASK_TYPES=image_points,image_boxes
+VITE_FEATURE_FLAG_JOBS_DISCOVERY=true
\ No newline at end of file
diff --git a/scripts/cvat/env-files/.env.human-app-server b/scripts/cvat/env-files/.env.human-app-server
new file mode 100644
index 0000000000..7eef62257c
--- /dev/null
+++ b/scripts/cvat/env-files/.env.human-app-server
@@ -0,0 +1,14 @@
+CHAIN_IDS_ENABLED=80002
+HCAPTCHA_LABELING_STATS_API_URL=disabled
+HCAPTCHA_LABELING_VERIFY_API_URL=disabled
+HCAPTCHA_LABELING_API_KEY=disabled
+# Should be the one you will use to access human-app-server API
+ALLOWED_HOST=localhost:5002
+HUMAN_APP_PASSWORD=HumanAppPassword
+# CORS
+CORS_ALLOWED_ORIGIN=*
+CORS_ALLOWED_HEADERS='Content-Type,Authorization,X-Requested-With,Accept,Origin'
+CORS_ENABLED=true
+IS_CACHE_TO_RESTART=false
+# FEATURE FLAGS
+FEATURE_FLAG_JOBS_DISCOVERY=true
diff --git a/scripts/cvat/env-files/.env.job-launcher b/scripts/cvat/env-files/.env.job-launcher
new file mode 100644
index 0000000000..8a3b1d9e9c
--- /dev/null
+++ b/scripts/cvat/env-files/.env.job-launcher
@@ -0,0 +1,70 @@
+# General
+COINMARKETCAP_API_KEY=replace_me
+
+# Database
+POSTGRES_DATABASE=job-launcher
+
+# Web3
+WEB3_PRIVATE_KEY=replace_me
+
+GAS_PRICE_MULTIPLIER=1
+
+# Encryption
+PGP_ENCRYPT=true
+PGP_PRIVATE_KEY="-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xYYEZ4+y/xYJKwYBBAHaRw8BAQdAlIkUUttKB25Zf/g3lf26lU15V4PcS6eM
+YiqfFUeyZGn+CQMIW8oNkxnBpSfgI4VBMN4ZamblXNYjg3u6HdSvuPrSjryR
+zEVPcE/QPTE+sljRLve2E4MEcGcs9c/JWxmD0Dlq7gpbctghQKkEbViwsj36
+L80lSm9iIExhdW5jaGVyIDxqb2ItbGF1bmNoZXJAbG9jYWwuYXBwPsKMBBAW
+CgA+BYJnj7L/BAsJBwgJkFvOlfsfiS2NAxUICgQWAAIBAhkBApsDAh4BFiEE
+nhDZweAQiTFNFnMEW86V+x+JLY0AAFrrAQDUTb30NvyMX1rvIAUdX7OnEQFu
+u+IkL52ZcvH0lJBHsAEA+iDL/03LCLIDK1g1l2mBZNUudEqncB0i0rAifeli
+hwLHiwRnj7L/EgorBgEEAZdVAQUBAQdASe/9TcJE/EnMLYE2K0o/ROxsRDi8
+cRtPEKSNVNLeCB4DAQgH/gkDCHtTPVsCMa9X4H1NkDo5Ijnyp74a2ZklE5l6
+coHvKRndTyT/UwxRPUo38pq3mI5U/bRCvrwFD6ehWWhlsfjm/D0Xsjj7J6jF
+uKxZgW+CGwfCeAQYFgoAKgWCZ4+y/wmQW86V+x+JLY0CmwwWIQSeENnB4BCJ
+MU0WcwRbzpX7H4ktjQAAZqoBAJ5Llw1V+5i9w9bOTS2NlQDSqtQAClCECEhD
+z9cFhU1RAQCBG62i7Cjsy+4RXxubBqVhNWCk02JhSn+vDAYT/TeqBA==
+=B2Ed
+-----END PGP PRIVATE KEY BLOCK-----"
+PGP_PASSPHRASE=job-launcher-pgp-password
+# Put it here just to easily set up KV later
+PGP_PUBLIC_KEY="-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+xjMEZ4+y/xYJKwYBBAHaRw8BAQdAlIkUUttKB25Zf/g3lf26lU15V4PcS6eM
+YiqfFUeyZGnNJUpvYiBMYXVuY2hlciA8am9iLWxhdW5jaGVyQGxvY2FsLmFw
+cD7CjAQQFgoAPgWCZ4+y/wQLCQcICZBbzpX7H4ktjQMVCAoEFgACAQIZAQKb
+AwIeARYhBJ4Q2cHgEIkxTRZzBFvOlfsfiS2NAABa6wEA1E299Db8jF9a7yAF
+HV+zpxEBbrviJC+dmXLx9JSQR7ABAPogy/9NywiyAytYNZdpgWTVLnRKp3Ad
+ItKwIn3pYocCzjgEZ4+y/xIKKwYBBAGXVQEFAQEHQEnv/U3CRPxJzC2BNitK
+P0TsbEQ4vHEbTxCkjVTS3ggeAwEIB8J4BBgWCgAqBYJnj7L/CZBbzpX7H4kt
+jQKbDBYhBJ4Q2cHgEIkxTRZzBFvOlfsfiS2NAABmqgEAnkuXDVX7mL3D1s5N
+LY2VANKq1AAKUIQISEPP1wWFTVEBAIEbraLsKOzL7hFfG5sGpWE1YKTTYmFK
+f68MBhP9N6oE
+=dNxu
+-----END PGP PUBLIC KEY BLOCK-----"
+
+FORTUNE_EXCHANGE_ORACLE_ADDRESS=disabled
+FORTUNE_RECORDING_ORACLE_ADDRESS=disabled
+HCAPTCHA_RECORDING_ORACLE_URI=disabled
+HCAPTCHA_REPUTATION_ORACLE_URI=disabled
+HCAPTCHA_ORACLE_ADDRESS=disabled
+
+# Auth
+JWT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgjwW8ZeWIKizY9pSl
+phyKfwYFp3aRHeMuV+jOKp49hX6hRANCAATeitytad5Rh0tx6AP/VHptsRvsZ+Xp
+/24PICdk4nsMxZEAe76InmWdqhud13JV76Jl02DVenFEJVM5IjRk+mLG
+-----END PRIVATE KEY-----"
+JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE3orcrWneUYdLcegD/1R6bbEb7Gfl
+6f9uDyAnZOJ7DMWRAHu+iJ5lnaobnddyVe+iZdNg1XpxRCVTOSI0ZPpixg==
+-----END PUBLIC KEY-----"
+
+# Stripe
+STRIPE_SECRET_KEY=replace_me
+STRIPE_API_VERSION=2022-11-15
+STRIPE_APP_NAME=Launcher Server Local
+STRIPE_APP_VERSION=1.0.0
+STRIPE_APP_INFO_URL=http://local.app
diff --git a/scripts/cvat/env-files/.env.job-launcher-client b/scripts/cvat/env-files/.env.job-launcher-client
new file mode 100644
index 0000000000..e649d58733
--- /dev/null
+++ b/scripts/cvat/env-files/.env.job-launcher-client
@@ -0,0 +1,9 @@
+VITE_APP_JOB_LAUNCHER_SERVER_URL=http://localhost:5005
+VITE_APP_WALLETCONNECT_PROJECT_ID=replace_me
+VITE_APP_STRIPE_PUBLISHABLE_KEY=replace_me
+VITE_APP_HCAPTCHA_SITE_KEY=10000000-ffff-ffff-ffff-000000000001
+VITE_APP_HCAPTCHA_EXCHANGE_URL=disabled
+VITE_APP_HCAPTCHA_LABELING_BASE_URL=disabled
+VITE_APP_ENVIRONMENT=testnet
+VITE_APP_RPC_URL_POLYGON_AMOY=https://rpc-amoy.polygon.technology
+VITE_APP_SUPPORTED_CHAINS=80002
diff --git a/scripts/cvat/env-files/.env.recording-oracle b/scripts/cvat/env-files/.env.recording-oracle
new file mode 100644
index 0000000000..6c8bbb1a88
--- /dev/null
+++ b/scripts/cvat/env-files/.env.recording-oracle
@@ -0,0 +1,50 @@
+# Polygon Amoy
+POLYGON_AMOY_PRIVATE_KEY=replace_me
+
+# Cron jobs
+PROCESS_EXCHANGE_ORACLE_WEBHOOKS_INT=10
+PROCESS_REPUTATION_ORACLE_WEBHOOKS_INT=10
+
+# Features
+ENABLE_CUSTOM_CLOUD_HOST="yes"
+
+
+# Encryption
+PGP_PRIVATE_KEY="-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xYYEZ4+5NBYJKwYBBAHaRw8BAQdAB8sDU5DxBk145aSEDgzsDqVvSbxoQffZ
+6wybUtZ/s+3+CQMI6+l2w9YuLXDgz7GAmnrbFaUciZFIfAzjng3ZjbABRoWI
+5+qwhJ4AITBpNzrju6SZV+NGlkgnYaljDk+cO+eIIL2N8D+v+UDGJokWy9P5
+PM0yQ1ZBVCByZWNvcmRpbmcgb3JhY2xlIDxyZWNvcmRpbmctb3JhY2xlQGxv
+Y2FsLmFwcD7CjAQQFgoAPgWCZ4+5NAQLCQcICZDA/EkpGIzNeAMVCAoEFgAC
+AQIZAQKbAwIeARYhBL5Bsw7o2pz/KrGZjMD8SSkYjM14AAA+wgEAzTwwMKXJ
+QUlIeUwmLR3OHrCuyHQIPWFzxLQcxESPftkA/1PTr20UozX+YNUV9XRLehJt
+3pmBtFzQZdndN3rTNJQKx4sEZ4+5NBIKKwYBBAGXVQEFAQEHQBJRjDJjbOVh
+k0ofZQv6VZF+GtvMzoZTErWOBSZnjJ5lAwEIB/4JAwhW7zmaNYAF+uA6JpwB
+zaAC1o2Cm5IRnBp66vdGG7RsyZBoca0R6aHht/UfzlrUwPKUmP13oTSQ1vxU
+Z5Fx+owW1V+w8ZDuxyN1zTWGgQh7wngEGBYKACoFgmePuTQJkMD8SSkYjM14
+ApsMFiEEvkGzDujanP8qsZmMwPxJKRiMzXgAANG2AQCA5PVDyVwo54y9Givv
+4V8HSyNHNVgxj0dLknOxJB3HSAEA/jO1djl9b99okxC3cgfic0ArMIT1V3gm
+9SSdFWQpfww=
+=X8yi
+-----END PGP PRIVATE KEY BLOCK-----"
+PGP_PASSPHRASE=rec-o-pgp-password
+PGP_PUBLIC_KEY="-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xYYEZ4+5NBYJKwYBBAHaRw8BAQdAB8sDU5DxBk145aSEDgzsDqVvSbxoQffZ
+6wybUtZ/s+3+CQMI6+l2w9YuLXDgz7GAmnrbFaUciZFIfAzjng3ZjbABRoWI
+5+qwhJ4AITBpNzrju6SZV+NGlkgnYaljDk+cO+eIIL2N8D+v+UDGJokWy9P5
+PM0yQ1ZBVCByZWNvcmRpbmcgb3JhY2xlIDxyZWNvcmRpbmctb3JhY2xlQGxv
+Y2FsLmFwcD7CjAQQFgoAPgWCZ4+5NAQLCQcICZDA/EkpGIzNeAMVCAoEFgAC
+AQIZAQKbAwIeARYhBL5Bsw7o2pz/KrGZjMD8SSkYjM14AAA+wgEAzTwwMKXJ
+QUlIeUwmLR3OHrCuyHQIPWFzxLQcxESPftkA/1PTr20UozX+YNUV9XRLehJt
+3pmBtFzQZdndN3rTNJQKx4sEZ4+5NBIKKwYBBAGXVQEFAQEHQBJRjDJjbOVh
+k0ofZQv6VZF+GtvMzoZTErWOBSZnjJ5lAwEIB/4JAwhW7zmaNYAF+uA6JpwB
+zaAC1o2Cm5IRnBp66vdGG7RsyZBoca0R6aHht/UfzlrUwPKUmP13oTSQ1vxU
+Z5Fx+owW1V+w8ZDuxyN1zTWGgQh7wngEGBYKACoFgmePuTQJkMD8SSkYjM14
+ApsMFiEEvkGzDujanP8qsZmMwPxJKRiMzXgAANG2AQCA5PVDyVwo54y9Givv
+4V8HSyNHNVgxj0dLknOxJB3HSAEA/jO1djl9b99okxC3cgfic0ArMIT1V3gm
+9SSdFWQpfww=
+=X8yi
+-----END PGP PRIVATE KEY BLOCK-----"
+PGP_PUBLIC_KEY_URL=http://minio:9000/recording-oracle/pgp-public-key
diff --git a/scripts/cvat/env-files/.env.reputation-oracle b/scripts/cvat/env-files/.env.reputation-oracle
new file mode 100644
index 0000000000..f53545576b
--- /dev/null
+++ b/scripts/cvat/env-files/.env.reputation-oracle
@@ -0,0 +1,48 @@
+# Auth
+JWT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg9T4TcNz4sFIvOZTE
+wBHX986G90H20Cryp4++7APQfu6hRANCAASQ96QPer3ose3gh+9jVRjVi6RN4R8r
+5evI9eFTnucq6FlcE9GtD6UwN4WlikdakaoD8rnvqf6sO+NsGAd9CIcq
+-----END PRIVATE KEY-----"
+
+# web3
+WEB3_PRIVATE_KEY=replace_me
+
+# Encryption
+PGP_ENCRYPT=true
+PGP_PRIVATE_KEY="-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+xYYEZ4+FFhYJKwYBBAHaRw8BAQdA/BEzpkXk107UOpQrUro20UxYryOW4g8x
+yAXIh2cH5ff+CQMI0h7UaI9LgBXgKHJF0y9LMaRyjZwkKYQa/yn5T1pfkgTn
+T2piULy9a+2w8EWyve2cv8zMBtZAcno75sV0X3BbMpkf9ru8hOoWQvkv8arN
+Wc01UmVwdXRhdGlvbiBPcmFjbGUgTG9jYWwgPHJlcHV0YXRpb24tb3JhY2xl
+QGxvY2FsLmFwcD7CjAQQFgoAPgWCZ4+FFgQLCQcICZCe6Z27JtHYsAMVCAoE
+FgACAQIZAQKbAwIeARYhBMXQP7WbhM4roaDkzZ7pnbsm0diwAACDdAEAkLuS
+rUp2eLBD2MEBP96wU8FqIUGsyju5Esd+yS7VGzIBAO8hmR8QEwk/+P2lKqLg
+6lgQnT0xubb7PqcNmJNoSX8Hx4sEZ4+FFhIKKwYBBAGXVQEFAQEHQJHtNaFR
+30ahNwXuUoYRyIA22K3B686H+mZCF5Nfy6JDAwEIB/4JAwj2Ltq6kZ0KfuC6
+78oX1t2wh/ZYJA9hZRa+8qyizfHZ9WKe7IWEXBW8yRc4IHNL0nYFCF5w5zoc
+NMHddSoQdIWhja8s5odZqA0uV1YaDHuOwngEGBYKACoFgmePhRYJkJ7pnbsm
+0diwApsMFiEExdA/tZuEziuhoOTNnumduybR2LAAAFNTAQDL0L2pHyi6CPPV
+fw6LtGasCu9iLT59kNj+gUabWgYVtQEApNxRcbFcYRyqmFjDDNXtyZhZB8Jj
+F8tN26blow3txgI=
+=68Rz
+-----END PGP PRIVATE KEY BLOCK-----"
+PGP_PASSPHRASE=rep-o-pgp-password
+# Put it here just to easily set up KV later
+PGP_PUBLIC_KEY="-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+xjMEZ4+FFhYJKwYBBAHaRw8BAQdA/BEzpkXk107UOpQrUro20UxYryOW4g8x
+yAXIh2cH5ffNNVJlcHV0YXRpb24gT3JhY2xlIExvY2FsIDxyZXB1dGF0aW9u
+LW9yYWNsZUBsb2NhbC5hcHA+wowEEBYKAD4FgmePhRYECwkHCAmQnumduybR
+2LADFQgKBBYAAgECGQECmwMCHgEWIQTF0D+1m4TOK6Gg5M2e6Z27JtHYsAAA
+g3QBAJC7kq1KdniwQ9jBAT/esFPBaiFBrMo7uRLHfsku1RsyAQDvIZkfEBMJ
+P/j9pSqi4OpYEJ09Mbm2+z6nDZiTaEl/B844BGePhRYSCisGAQQBl1UBBQEB
+B0CR7TWhUd9GoTcF7lKGEciANtitwevOh/pmQheTX8uiQwMBCAfCeAQYFgoA
+KgWCZ4+FFgmQnumduybR2LACmwwWIQTF0D+1m4TOK6Gg5M2e6Z27JtHYsAAA
+U1MBAMvQvakfKLoI89V/Dou0ZqwK72ItPn2Q2P6BRptaBhW1AQCk3FFxsVxh
+HKqYWMMM1e3JmFkHwmMXy03bpuWjDe3GAg==
+=pqBc
+-----END PGP PUBLIC KEY BLOCK-----"
+
+KYC_API_KEY=disabled
diff --git a/scripts/cvat/initdb/create-dbs.sql b/scripts/cvat/initdb/create-dbs.sql
new file mode 100644
index 0000000000..3b5f93e98e
--- /dev/null
+++ b/scripts/cvat/initdb/create-dbs.sql
@@ -0,0 +1,4 @@
+CREATE DATABASE "reputation-oracle";
+CREATE DATABASE "exchange-oracle";
+CREATE DATABASE "recording-oracle";
+CREATE DATABASE "job-launcher";
diff --git a/yarn.lock b/yarn.lock
index 41054eae18..6daabcceb3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3278,7 +3278,7 @@
jsonc-parser "3.3.1"
pluralize "8.0.0"
-"@nestjs/serve-static@^4.0.1":
+"@nestjs/serve-static@^4.0.1", "@nestjs/serve-static@^4.0.2":
version "4.0.2"
resolved "https://registry.yarnpkg.com/@nestjs/serve-static/-/serve-static-4.0.2.tgz#f003bbd90922bdc73d0261edacf001dfef174c96"
integrity sha512-cT0vdWN5ar7jDI2NKbhf4LcwJzU4vS5sVpMkVrHuyLcltbrz6JdGi1TfIMMatP2pNiq5Ie/uUdPSFDVaZX/URQ==
@@ -5495,7 +5495,7 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
-"@types/jsonwebtoken@*":
+"@types/jsonwebtoken@*", "@types/jsonwebtoken@^9.0.7":
version "9.0.7"
resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz#e49b96c2b29356ed462e9708fc73b833014727d2"
integrity sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==
@@ -5521,6 +5521,11 @@
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.13.tgz#786e2d67cfd95e32862143abe7463a7f90c300eb"
integrity sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==
+"@types/lodash@^4.17.14":
+ version "4.17.14"
+ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.14.tgz#bafc053533f4cdc5fcc9635af46a963c1f3deaff"
+ integrity sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==
+
"@types/long@^4.0.0", "@types/long@^4.0.1":
version "4.0.2"
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
@@ -7761,7 +7766,7 @@ bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1:
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70"
integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
-body-parser@1.20.3, body-parser@^1.20.0, body-parser@^1.20.2:
+body-parser@1.20.3, body-parser@^1.20.0, body-parser@^1.20.2, body-parser@^1.20.3:
version "1.20.3"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6"
integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==
@@ -13900,7 +13905,7 @@ jsonschema@^1.2.4, jsonschema@^1.4.1:
resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.1.tgz#cc4c3f0077fb4542982973d8a083b6b34f482dab"
integrity sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==
-jsonwebtoken@9.0.2, jsonwebtoken@^9.0.0:
+jsonwebtoken@9.0.2, jsonwebtoken@^9.0.0, jsonwebtoken@^9.0.2:
version "9.0.2"
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3"
integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==
@@ -14579,7 +14584,7 @@ matchstick-as@^0.6.0:
dependencies:
wabt "1.0.24"
-material-react-table@^3.0.1:
+material-react-table@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/material-react-table/-/material-react-table-3.0.1.tgz#a6d592a1e370acfd453c37f1deaa870c47e7bf5b"
integrity sha512-RP+bnpsOAH5j6zwP04u9HB37fyqbd6mVv9mkT4IUJC3e3gEqixZmkNdJMVM1ZVHoq7yIaM381xf22mpBVe0IaA==