diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js index 7a3a8d802..e99c48c09 100644 --- a/backend/.eslintrc.js +++ b/backend/.eslintrc.js @@ -1,27 +1,39 @@ +/* eslint-env node */ module.exports = { - root: true, env: { - browser: true, - es2021: true + es6: true, + node: true }, - extends: ["airbnb-base", "airbnb-typescript/base", "prettier"], - plugins: ["prettier", "simple-import-sort", "import"], + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-type-checked", + "airbnb-base", + "airbnb-typescript/base", + "plugin:prettier/recommended", + "prettier" + ], + plugins: ["@typescript-eslint", "simple-import-sort", "import"], + parser: "@typescript-eslint/parser", parserOptions: { - ecmaVersion: "latest", + project: true, sourceType: "module", - project: "./tsconfig.json", tsconfigRootDir: __dirname }, + root: true, rules: { "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-unsafe-enum-comparison": "off", + "no-void": "off", "consistent-return": "off", // my style "import/order": "off", // for simple-import-order "import/prefer-default-export": "off", // why "no-restricted-syntax": "off", + // importing rules + "simple-import-sort/exports": "error", "import/first": "error", "import/newline-after-import": "error", "import/no-duplicates": "error", - "simple-import-sort/exports": "error", "simple-import-sort/imports": [ "warn", { @@ -45,12 +57,5 @@ module.exports = { ] } ] - }, - settings: { - "import/resolver": { - typescript: { - project: ["./tsconfig.json"] - } - } } }; diff --git a/backend/package-lock.json b/backend/package-lock.json index 6f8a6d33e..d1d12ad2e 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -25,6 +25,8 @@ "@octokit/webhooks-types": "^7.3.1", "@serdnam/pino-cloudwatch-transport": "^1.0.4", "@sindresorhus/slugify": "^2.2.1", + "@typescript-eslint/eslint-plugin": "^6.20.0", + "@typescript-eslint/parser": "^6.20.0", "@ucast/mongo2js": "^1.3.4", "ajv": "^8.12.0", "argon2": "^0.31.2", @@ -34,6 +36,8 @@ "bcrypt": "^5.1.1", "bullmq": "^5.1.1", "dotenv": "^16.3.1", + "eslint": "^8.56.0", + "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.1.0", "fastify": "^4.24.3", "fastify-plugin": "^4.5.1", @@ -80,10 +84,6 @@ "@types/picomatch": "^2.3.3", "@types/prompt-sync": "^4.2.3", "@types/uuid": "^9.0.7", - "@typescript-eslint/eslint-plugin": "^6.13.2", - "@typescript-eslint/parser": "^6.13.2", - "eslint": "^8.56.0", - "eslint-config-airbnb-base": "^15.0.0", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.29.1", @@ -4530,15 +4530,15 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.2.tgz", - "integrity": "sha512-3+9OGAWHhk4O1LlcwLBONbdXsAhLjyCFogJY/cWy2lxdVJ2JrcTF2pTGMaLl2AE7U1l31n8Py4a8bx5DLf/0dQ==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.20.0.tgz", + "integrity": "sha512-fTwGQUnjhoYHeSF6m5pWNkzmDDdsKELYrOBxhjMrofPqCkoC2k3B2wvGHFxa1CTIqkEn88nlW1HVMztjo2K8Hg==", "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/type-utils": "6.13.2", - "@typescript-eslint/utils": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", + "@typescript-eslint/scope-manager": "6.20.0", + "@typescript-eslint/type-utils": "6.20.0", + "@typescript-eslint/utils": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -4585,14 +4585,14 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/@typescript-eslint/parser": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.2.tgz", - "integrity": "sha512-MUkcC+7Wt/QOGeVlM8aGGJZy1XV5YKjTpq9jK6r6/iLsGXhBVaGP5N0UYvFsu9BFlSpwY9kMretzdBH01rkRXg==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.20.0.tgz", + "integrity": "sha512-bYerPDF/H5v6V76MdMYhjwmwgMA+jlPVqjSDq2cRqMi8bP5sR3Z+RLOiOMad3nsnmDVmn2gAFCyNgh/dIrfP/w==", "dependencies": { - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/typescript-estree": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", + "@typescript-eslint/scope-manager": "6.20.0", + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/typescript-estree": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0", "debug": "^4.3.4" }, "engines": { @@ -4633,12 +4633,12 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.2.tgz", - "integrity": "sha512-CXQA0xo7z6x13FeDYCgBkjWzNqzBn8RXaE3QVQVIUm74fWJLkJkaHmHdKStrxQllGh6Q4eUGyNpMe0b1hMkXFA==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.20.0.tgz", + "integrity": "sha512-p4rvHQRDTI1tGGMDFQm+GtxP1ZHyAh64WANVoyEcNMpaTFn3ox/3CcgtIlELnRfKzSs/DwYlDccJEtr3O6qBvA==", "dependencies": { - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2" + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -4649,12 +4649,12 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.2.tgz", - "integrity": "sha512-Qr6ssS1GFongzH2qfnWKkAQmMUyZSyOr0W54nZNU1MDfo+U4Mv3XveeLZzadc/yq8iYhQZHYT+eoXJqnACM1tw==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.20.0.tgz", + "integrity": "sha512-qnSobiJQb1F5JjN0YDRPHruQTrX7ICsmltXhkV536mp4idGAYrIyr47zF/JmkJtEcAVnIz4gUYJ7gOZa6SmN4g==", "dependencies": { - "@typescript-eslint/typescript-estree": "6.13.2", - "@typescript-eslint/utils": "6.13.2", + "@typescript-eslint/typescript-estree": "6.20.0", + "@typescript-eslint/utils": "6.20.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -4696,9 +4696,9 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/@typescript-eslint/types": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.2.tgz", - "integrity": "sha512-7sxbQ+EMRubQc3wTfTsycgYpSujyVbI1xw+3UMRUcrhSy+pN09y/lWzeKDbvhoqcRbHdc+APLs/PWYi/cisLPg==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.20.0.tgz", + "integrity": "sha512-MM9mfZMAhiN4cOEcUOEx+0HmuaW3WBfukBZPCfwSqFnQy0grXYtngKCqpQN339X3RrwtzspWJrpbrupKYUSBXQ==", "engines": { "node": "^16.0.0 || >=18.0.0" }, @@ -4708,15 +4708,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.2.tgz", - "integrity": "sha512-SuD8YLQv6WHnOEtKv8D6HZUzOub855cfPnPMKvdM/Bh1plv1f7Q/0iFUDLKKlxHcEstQnaUU4QZskgQq74t+3w==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.20.0.tgz", + "integrity": "sha512-RnRya9q5m6YYSpBN7IzKu9FmLcYtErkDkc8/dKv81I9QiLLtVBHrjz+Ev/crAqgMNW2FCsoZF4g2QUylMnJz+g==", "dependencies": { - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/visitor-keys": "6.13.2", + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/visitor-keys": "6.20.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", + "minimatch": "9.0.3", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" }, @@ -4733,6 +4734,14 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -4749,22 +4758,36 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/@typescript-eslint/utils": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.2.tgz", - "integrity": "sha512-b9Ptq4eAZUym4idijCRzl61oPCwwREcfDI8xGk751Vhzig5fFZR9CyzDz4Sp/nxSLBYxUPyh4QdIDqWykFhNmQ==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.20.0.tgz", + "integrity": "sha512-/EKuw+kRu2vAqCoDwDCBtDRU6CTKbUmwwI7SH7AashZ+W+7o8eiyy6V2cdOqN49KsTcASWsC5QeghYuRDTyOOg==", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.13.2", - "@typescript-eslint/types": "6.13.2", - "@typescript-eslint/typescript-estree": "6.13.2", + "@typescript-eslint/scope-manager": "6.20.0", + "@typescript-eslint/types": "6.20.0", + "@typescript-eslint/typescript-estree": "6.20.0", "semver": "^7.5.4" }, "engines": { @@ -4779,11 +4802,11 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.2.tgz", - "integrity": "sha512-OGznFs0eAQXJsp+xSd6k/O1UbFi/K/L7WjqeRoFE7vadjAF9y0uppXhYNQNEqygjou782maGClOoZwPqF0Drlw==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.20.0.tgz", + "integrity": "sha512-E8Cp98kRe4gKHjJD4NExXKz/zOJ1A2hhZc+IMVD6i7w4yjIvh6VyuRI0gRtxAsXtoC35uGMaQ9rjI2zJaXDEAw==", "dependencies": { - "@typescript-eslint/types": "6.13.2", + "@typescript-eslint/types": "6.20.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { diff --git a/backend/package.json b/backend/package.json index d379d54a8..39aed4e34 100644 --- a/backend/package.json +++ b/backend/package.json @@ -45,10 +45,6 @@ "@types/picomatch": "^2.3.3", "@types/prompt-sync": "^4.2.3", "@types/uuid": "^9.0.7", - "@typescript-eslint/eslint-plugin": "^6.13.2", - "@typescript-eslint/parser": "^6.13.2", - "eslint": "^8.56.0", - "eslint-config-airbnb-base": "^15.0.0", "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.29.1", @@ -83,6 +79,8 @@ "@octokit/webhooks-types": "^7.3.1", "@serdnam/pino-cloudwatch-transport": "^1.0.4", "@sindresorhus/slugify": "^2.2.1", + "@typescript-eslint/eslint-plugin": "^6.20.0", + "@typescript-eslint/parser": "^6.20.0", "@ucast/mongo2js": "^1.3.4", "ajv": "^8.12.0", "argon2": "^0.31.2", @@ -92,6 +90,8 @@ "bcrypt": "^5.1.1", "bullmq": "^5.1.1", "dotenv": "^16.3.1", + "eslint": "^8.56.0", + "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.1.0", "fastify": "^4.24.3", "fastify-plugin": "^4.5.1", diff --git a/backend/src/db/migrations/20231228075011_identity-access-token.ts b/backend/src/db/migrations/20231228075011_identity-access-token.ts index 33c5f96ef..e8e26fc70 100644 --- a/backend/src/db/migrations/20231228075011_identity-access-token.ts +++ b/backend/src/db/migrations/20231228075011_identity-access-token.ts @@ -19,7 +19,7 @@ export async function up(knex: Knex): Promise { .references("id") .inTable(TableName.IdentityUaClientSecret) .onDelete("CASCADE"); - t.uuid("identityId").notNullable(); + t.uuid("identityId").notNullable(); t.foreign("identityId").references("id").inTable(TableName.Identity).onDelete("CASCADE"); t.timestamps(true, true, true); }); diff --git a/backend/src/db/migrations/20240111051011_secret-scanning.ts b/backend/src/db/migrations/20240111051011_secret-scanning.ts index af011d558..28a57bf08 100644 --- a/backend/src/db/migrations/20240111051011_secret-scanning.ts +++ b/backend/src/db/migrations/20240111051011_secret-scanning.ts @@ -15,7 +15,7 @@ export async function up(knex: Knex): Promise { t.timestamps(true, true, true); }); } - createOnUpdateTrigger(knex, TableName.GitAppInstallSession); + await createOnUpdateTrigger(knex, TableName.GitAppInstallSession); if (!(await knex.schema.hasTable(TableName.GitAppOrg))) { await knex.schema.createTable(TableName.GitAppOrg, (t) => { @@ -28,7 +28,7 @@ export async function up(knex: Knex): Promise { t.timestamps(true, true, true); }); } - createOnUpdateTrigger(knex, TableName.GitAppOrg); + await createOnUpdateTrigger(knex, TableName.GitAppOrg); if (!(await knex.schema.hasTable(TableName.SecretScanningGitRisk))) { await knex.schema.createTable(TableName.SecretScanningGitRisk, (t) => { @@ -66,7 +66,7 @@ export async function up(knex: Knex): Promise { t.timestamps(true, true, true); }); } - createOnUpdateTrigger(knex, TableName.SecretScanningGitRisk); + await createOnUpdateTrigger(knex, TableName.SecretScanningGitRisk); } export async function down(knex: Knex): Promise { diff --git a/backend/src/db/schemas/api-keys.ts b/backend/src/db/schemas/api-keys.ts index c3f384a5a..ff29a54e1 100644 --- a/backend/src/db/schemas/api-keys.ts +++ b/backend/src/db/schemas/api-keys.ts @@ -15,7 +15,7 @@ export const ApiKeysSchema = z.object({ secretHash: z.string(), createdAt: z.date(), updatedAt: z.date(), - userId: z.string().uuid(), + userId: z.string().uuid() }); export type TApiKeys = z.infer; diff --git a/backend/src/db/schemas/audit-logs.ts b/backend/src/db/schemas/audit-logs.ts index 90c389b94..f7143bb57 100644 --- a/backend/src/db/schemas/audit-logs.ts +++ b/backend/src/db/schemas/audit-logs.ts @@ -20,7 +20,7 @@ export const AuditLogsSchema = z.object({ createdAt: z.date(), updatedAt: z.date(), orgId: z.string().uuid().nullable().optional(), - projectId: z.string().nullable().optional(), + projectId: z.string().nullable().optional() }); export type TAuditLogs = z.infer; diff --git a/backend/src/db/schemas/auth-token-sessions.ts b/backend/src/db/schemas/auth-token-sessions.ts index 9dbf8e09f..46ed7c201 100644 --- a/backend/src/db/schemas/auth-token-sessions.ts +++ b/backend/src/db/schemas/auth-token-sessions.ts @@ -16,7 +16,7 @@ export const AuthTokenSessionsSchema = z.object({ lastUsed: z.date(), createdAt: z.date(), updatedAt: z.date(), - userId: z.string().uuid(), + userId: z.string().uuid() }); export type TAuthTokenSessions = z.infer; diff --git a/backend/src/db/schemas/auth-tokens.ts b/backend/src/db/schemas/auth-tokens.ts index 4a612b11d..9ae8eed44 100644 --- a/backend/src/db/schemas/auth-tokens.ts +++ b/backend/src/db/schemas/auth-tokens.ts @@ -17,7 +17,7 @@ export const AuthTokensSchema = z.object({ createdAt: z.date(), updatedAt: z.date(), userId: z.string().uuid().nullable().optional(), - orgId: z.string().uuid().nullable().optional(), + orgId: z.string().uuid().nullable().optional() }); export type TAuthTokens = z.infer; diff --git a/backend/src/db/schemas/backup-private-key.ts b/backend/src/db/schemas/backup-private-key.ts index 9b6e787b1..5930bbd4a 100644 --- a/backend/src/db/schemas/backup-private-key.ts +++ b/backend/src/db/schemas/backup-private-key.ts @@ -18,7 +18,7 @@ export const BackupPrivateKeySchema = z.object({ verifier: z.string(), createdAt: z.date(), updatedAt: z.date(), - userId: z.string().uuid(), + userId: z.string().uuid() }); export type TBackupPrivateKey = z.infer; diff --git a/backend/src/db/schemas/git-app-install-sessions.ts b/backend/src/db/schemas/git-app-install-sessions.ts index 16f62eab7..6c6db40ea 100644 --- a/backend/src/db/schemas/git-app-install-sessions.ts +++ b/backend/src/db/schemas/git-app-install-sessions.ts @@ -13,7 +13,7 @@ export const GitAppInstallSessionsSchema = z.object({ userId: z.string().uuid().nullable().optional(), orgId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TGitAppInstallSessions = z.infer; diff --git a/backend/src/db/schemas/git-app-org.ts b/backend/src/db/schemas/git-app-org.ts index f5226811d..57e0d474a 100644 --- a/backend/src/db/schemas/git-app-org.ts +++ b/backend/src/db/schemas/git-app-org.ts @@ -13,7 +13,7 @@ export const GitAppOrgSchema = z.object({ userId: z.string().uuid(), orgId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TGitAppOrg = z.infer; diff --git a/backend/src/db/schemas/identities.ts b/backend/src/db/schemas/identities.ts index b8ff6c36f..005adf025 100644 --- a/backend/src/db/schemas/identities.ts +++ b/backend/src/db/schemas/identities.ts @@ -12,7 +12,7 @@ export const IdentitiesSchema = z.object({ name: z.string(), authMethod: z.string().nullable().optional(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TIdentities = z.infer; diff --git a/backend/src/db/schemas/identity-access-tokens.ts b/backend/src/db/schemas/identity-access-tokens.ts index d36291ab9..cbd71e5c5 100644 --- a/backend/src/db/schemas/identity-access-tokens.ts +++ b/backend/src/db/schemas/identity-access-tokens.ts @@ -19,7 +19,7 @@ export const IdentityAccessTokensSchema = z.object({ identityUAClientSecretId: z.string().nullable().optional(), identityId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TIdentityAccessTokens = z.infer; diff --git a/backend/src/db/schemas/identity-org-memberships.ts b/backend/src/db/schemas/identity-org-memberships.ts index c5c9a0f61..90cf230d0 100644 --- a/backend/src/db/schemas/identity-org-memberships.ts +++ b/backend/src/db/schemas/identity-org-memberships.ts @@ -14,9 +14,11 @@ export const IdentityOrgMembershipsSchema = z.object({ orgId: z.string().uuid(), createdAt: z.date(), updatedAt: z.date(), - identityId: z.string().uuid(), + identityId: z.string().uuid() }); export type TIdentityOrgMemberships = z.infer; export type TIdentityOrgMembershipsInsert = Omit; -export type TIdentityOrgMembershipsUpdate = Partial>; +export type TIdentityOrgMembershipsUpdate = Partial< + Omit +>; diff --git a/backend/src/db/schemas/identity-project-memberships.ts b/backend/src/db/schemas/identity-project-memberships.ts index 9a57952a4..9c6bbf436 100644 --- a/backend/src/db/schemas/identity-project-memberships.ts +++ b/backend/src/db/schemas/identity-project-memberships.ts @@ -14,9 +14,11 @@ export const IdentityProjectMembershipsSchema = z.object({ projectId: z.string(), identityId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TIdentityProjectMemberships = z.infer; export type TIdentityProjectMembershipsInsert = Omit; -export type TIdentityProjectMembershipsUpdate = Partial>; +export type TIdentityProjectMembershipsUpdate = Partial< + Omit +>; diff --git a/backend/src/db/schemas/identity-ua-client-secrets.ts b/backend/src/db/schemas/identity-ua-client-secrets.ts index f17b1ed7f..788a3b9ad 100644 --- a/backend/src/db/schemas/identity-ua-client-secrets.ts +++ b/backend/src/db/schemas/identity-ua-client-secrets.ts @@ -19,9 +19,11 @@ export const IdentityUaClientSecretsSchema = z.object({ isClientSecretRevoked: z.boolean().default(false), createdAt: z.date(), updatedAt: z.date(), - identityUAId: z.string().uuid(), + identityUAId: z.string().uuid() }); export type TIdentityUaClientSecrets = z.infer; export type TIdentityUaClientSecretsInsert = Omit; -export type TIdentityUaClientSecretsUpdate = Partial>; +export type TIdentityUaClientSecretsUpdate = Partial< + Omit +>; diff --git a/backend/src/db/schemas/identity-universal-auths.ts b/backend/src/db/schemas/identity-universal-auths.ts index 1dbc61ea8..c05ceedae 100644 --- a/backend/src/db/schemas/identity-universal-auths.ts +++ b/backend/src/db/schemas/identity-universal-auths.ts @@ -17,9 +17,11 @@ export const IdentityUniversalAuthsSchema = z.object({ accessTokenTrustedIps: z.unknown(), createdAt: z.date(), updatedAt: z.date(), - identityId: z.string().uuid(), + identityId: z.string().uuid() }); export type TIdentityUniversalAuths = z.infer; export type TIdentityUniversalAuthsInsert = Omit; -export type TIdentityUniversalAuthsUpdate = Partial>; +export type TIdentityUniversalAuthsUpdate = Partial< + Omit +>; diff --git a/backend/src/db/schemas/incident-contacts.ts b/backend/src/db/schemas/incident-contacts.ts index c1492e0fa..431bf05ab 100644 --- a/backend/src/db/schemas/incident-contacts.ts +++ b/backend/src/db/schemas/incident-contacts.ts @@ -12,7 +12,7 @@ export const IncidentContactsSchema = z.object({ email: z.string(), createdAt: z.date(), updatedAt: z.date(), - orgId: z.string().uuid(), + orgId: z.string().uuid() }); export type TIncidentContacts = z.infer; diff --git a/backend/src/db/schemas/integration-auths.ts b/backend/src/db/schemas/integration-auths.ts index d2983658c..db602c0af 100644 --- a/backend/src/db/schemas/integration-auths.ts +++ b/backend/src/db/schemas/integration-auths.ts @@ -29,7 +29,7 @@ export const IntegrationAuthsSchema = z.object({ keyEncoding: z.string(), projectId: z.string(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TIntegrationAuths = z.infer; diff --git a/backend/src/db/schemas/integrations.ts b/backend/src/db/schemas/integrations.ts index b2163dc4d..62f73d190 100644 --- a/backend/src/db/schemas/integrations.ts +++ b/backend/src/db/schemas/integrations.ts @@ -25,9 +25,9 @@ export const IntegrationsSchema = z.object({ metadata: z.unknown().nullable().optional(), integrationAuthId: z.string().uuid(), envId: z.string().uuid(), - secretPath: z.string().default('/'), + secretPath: z.string().default("/"), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TIntegrations = z.infer; diff --git a/backend/src/db/schemas/org-bots.ts b/backend/src/db/schemas/org-bots.ts index 400ab19c8..b328f1aaf 100644 --- a/backend/src/db/schemas/org-bots.ts +++ b/backend/src/db/schemas/org-bots.ts @@ -23,7 +23,7 @@ export const OrgBotsSchema = z.object({ privateKeyKeyEncoding: z.string(), orgId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TOrgBots = z.infer; diff --git a/backend/src/db/schemas/org-memberships.ts b/backend/src/db/schemas/org-memberships.ts index 932c84d00..b2fffa117 100644 --- a/backend/src/db/schemas/org-memberships.ts +++ b/backend/src/db/schemas/org-memberships.ts @@ -10,13 +10,13 @@ import { TImmutableDBKeys } from "./models"; export const OrgMembershipsSchema = z.object({ id: z.string().uuid(), role: z.string(), - status: z.string().default('invited'), + status: z.string().default("invited"), inviteEmail: z.string().nullable().optional(), createdAt: z.date(), updatedAt: z.date(), userId: z.string().uuid().nullable().optional(), orgId: z.string().uuid(), - roleId: z.string().uuid().nullable().optional(), + roleId: z.string().uuid().nullable().optional() }); export type TOrgMemberships = z.infer; diff --git a/backend/src/db/schemas/org-roles.ts b/backend/src/db/schemas/org-roles.ts index 9718cdb26..72b582f96 100644 --- a/backend/src/db/schemas/org-roles.ts +++ b/backend/src/db/schemas/org-roles.ts @@ -15,7 +15,7 @@ export const OrgRolesSchema = z.object({ permissions: z.unknown(), createdAt: z.date(), updatedAt: z.date(), - orgId: z.string().uuid(), + orgId: z.string().uuid() }); export type TOrgRoles = z.infer; diff --git a/backend/src/db/schemas/organizations.ts b/backend/src/db/schemas/organizations.ts index 539217c00..e0f70d1c0 100644 --- a/backend/src/db/schemas/organizations.ts +++ b/backend/src/db/schemas/organizations.ts @@ -13,7 +13,7 @@ export const OrganizationsSchema = z.object({ customerId: z.string().nullable().optional(), slug: z.string(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TOrganizations = z.infer; diff --git a/backend/src/db/schemas/project-bots.ts b/backend/src/db/schemas/project-bots.ts index 90ced9b3e..c68576943 100644 --- a/backend/src/db/schemas/project-bots.ts +++ b/backend/src/db/schemas/project-bots.ts @@ -22,7 +22,7 @@ export const ProjectBotsSchema = z.object({ projectId: z.string(), senderId: z.string().uuid().nullable().optional(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TProjectBots = z.infer; diff --git a/backend/src/db/schemas/project-environments.ts b/backend/src/db/schemas/project-environments.ts index aa3e392c7..8b95dbba0 100644 --- a/backend/src/db/schemas/project-environments.ts +++ b/backend/src/db/schemas/project-environments.ts @@ -14,7 +14,7 @@ export const ProjectEnvironmentsSchema = z.object({ position: z.number(), projectId: z.string(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TProjectEnvironments = z.infer; diff --git a/backend/src/db/schemas/project-keys.ts b/backend/src/db/schemas/project-keys.ts index 64e33d574..720cd79bf 100644 --- a/backend/src/db/schemas/project-keys.ts +++ b/backend/src/db/schemas/project-keys.ts @@ -15,7 +15,7 @@ export const ProjectKeysSchema = z.object({ senderId: z.string().uuid().nullable().optional(), projectId: z.string(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TProjectKeys = z.infer; diff --git a/backend/src/db/schemas/project-memberships.ts b/backend/src/db/schemas/project-memberships.ts index c98befb38..b9f191a84 100644 --- a/backend/src/db/schemas/project-memberships.ts +++ b/backend/src/db/schemas/project-memberships.ts @@ -14,7 +14,7 @@ export const ProjectMembershipsSchema = z.object({ updatedAt: z.date(), userId: z.string().uuid(), projectId: z.string(), - roleId: z.string().uuid().nullable().optional(), + roleId: z.string().uuid().nullable().optional() }); export type TProjectMemberships = z.infer; diff --git a/backend/src/db/schemas/project-roles.ts b/backend/src/db/schemas/project-roles.ts index 190dd1cec..1946ab5e1 100644 --- a/backend/src/db/schemas/project-roles.ts +++ b/backend/src/db/schemas/project-roles.ts @@ -15,7 +15,7 @@ export const ProjectRolesSchema = z.object({ permissions: z.unknown(), createdAt: z.date(), updatedAt: z.date(), - projectId: z.string(), + projectId: z.string() }); export type TProjectRoles = z.infer; diff --git a/backend/src/db/schemas/projects.ts b/backend/src/db/schemas/projects.ts index 005e4bbde..296fa421e 100644 --- a/backend/src/db/schemas/projects.ts +++ b/backend/src/db/schemas/projects.ts @@ -14,7 +14,7 @@ export const ProjectsSchema = z.object({ autoCapitalization: z.boolean().default(true).nullable().optional(), orgId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TProjects = z.infer; diff --git a/backend/src/db/schemas/saml-configs.ts b/backend/src/db/schemas/saml-configs.ts index 392fb2bef..4633384b9 100644 --- a/backend/src/db/schemas/saml-configs.ts +++ b/backend/src/db/schemas/saml-configs.ts @@ -22,7 +22,7 @@ export const SamlConfigsSchema = z.object({ certTag: z.string().nullable().optional(), createdAt: z.date(), updatedAt: z.date(), - orgId: z.string().uuid(), + orgId: z.string().uuid() }); export type TSamlConfigs = z.infer; diff --git a/backend/src/db/schemas/secret-approval-policies-approvers.ts b/backend/src/db/schemas/secret-approval-policies-approvers.ts index c6fb75f06..4236f79da 100644 --- a/backend/src/db/schemas/secret-approval-policies-approvers.ts +++ b/backend/src/db/schemas/secret-approval-policies-approvers.ts @@ -12,9 +12,16 @@ export const SecretApprovalPoliciesApproversSchema = z.object({ approverId: z.string().uuid(), policyId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); -export type TSecretApprovalPoliciesApprovers = z.infer; -export type TSecretApprovalPoliciesApproversInsert = Omit; -export type TSecretApprovalPoliciesApproversUpdate = Partial>; +export type TSecretApprovalPoliciesApprovers = z.infer< + typeof SecretApprovalPoliciesApproversSchema +>; +export type TSecretApprovalPoliciesApproversInsert = Omit< + TSecretApprovalPoliciesApprovers, + TImmutableDBKeys +>; +export type TSecretApprovalPoliciesApproversUpdate = Partial< + Omit +>; diff --git a/backend/src/db/schemas/secret-approval-policies.ts b/backend/src/db/schemas/secret-approval-policies.ts index ec859bb4e..7ad466447 100644 --- a/backend/src/db/schemas/secret-approval-policies.ts +++ b/backend/src/db/schemas/secret-approval-policies.ts @@ -14,9 +14,11 @@ export const SecretApprovalPoliciesSchema = z.object({ approvals: z.number().default(1), envId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretApprovalPolicies = z.infer; export type TSecretApprovalPoliciesInsert = Omit; -export type TSecretApprovalPoliciesUpdate = Partial>; +export type TSecretApprovalPoliciesUpdate = Partial< + Omit +>; diff --git a/backend/src/db/schemas/secret-approval-request-secret-tags.ts b/backend/src/db/schemas/secret-approval-request-secret-tags.ts index 47e11e6a9..3929c146c 100644 --- a/backend/src/db/schemas/secret-approval-request-secret-tags.ts +++ b/backend/src/db/schemas/secret-approval-request-secret-tags.ts @@ -12,9 +12,16 @@ export const SecretApprovalRequestSecretTagsSchema = z.object({ secretId: z.string().uuid(), tagId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); -export type TSecretApprovalRequestSecretTags = z.infer; -export type TSecretApprovalRequestSecretTagsInsert = Omit; -export type TSecretApprovalRequestSecretTagsUpdate = Partial>; +export type TSecretApprovalRequestSecretTags = z.infer< + typeof SecretApprovalRequestSecretTagsSchema +>; +export type TSecretApprovalRequestSecretTagsInsert = Omit< + TSecretApprovalRequestSecretTags, + TImmutableDBKeys +>; +export type TSecretApprovalRequestSecretTagsUpdate = Partial< + Omit +>; diff --git a/backend/src/db/schemas/secret-approval-requests-reviewers.ts b/backend/src/db/schemas/secret-approval-requests-reviewers.ts index 4ed9b50a1..3b14c0eb5 100644 --- a/backend/src/db/schemas/secret-approval-requests-reviewers.ts +++ b/backend/src/db/schemas/secret-approval-requests-reviewers.ts @@ -13,9 +13,16 @@ export const SecretApprovalRequestsReviewersSchema = z.object({ status: z.string(), requestId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); -export type TSecretApprovalRequestsReviewers = z.infer; -export type TSecretApprovalRequestsReviewersInsert = Omit; -export type TSecretApprovalRequestsReviewersUpdate = Partial>; +export type TSecretApprovalRequestsReviewers = z.infer< + typeof SecretApprovalRequestsReviewersSchema +>; +export type TSecretApprovalRequestsReviewersInsert = Omit< + TSecretApprovalRequestsReviewers, + TImmutableDBKeys +>; +export type TSecretApprovalRequestsReviewersUpdate = Partial< + Omit +>; diff --git a/backend/src/db/schemas/secret-approval-requests-secrets.ts b/backend/src/db/schemas/secret-approval-requests-secrets.ts index db98bda17..9dbd29db2 100644 --- a/backend/src/db/schemas/secret-approval-requests-secrets.ts +++ b/backend/src/db/schemas/secret-approval-requests-secrets.ts @@ -23,17 +23,22 @@ export const SecretApprovalRequestsSecretsSchema = z.object({ secretReminderNote: z.string().nullable().optional(), secretReminderRepeatDays: z.number().nullable().optional(), skipMultilineEncoding: z.boolean().default(false).nullable().optional(), - algorithm: z.string().default('aes-256-gcm'), - keyEncoding: z.string().default('utf8'), + algorithm: z.string().default("aes-256-gcm"), + keyEncoding: z.string().default("utf8"), metadata: z.unknown().nullable().optional(), createdAt: z.date(), updatedAt: z.date(), requestId: z.string().uuid(), op: z.string(), secretId: z.string().uuid().nullable().optional(), - secretVersion: z.string().uuid().nullable().optional(), + secretVersion: z.string().uuid().nullable().optional() }); export type TSecretApprovalRequestsSecrets = z.infer; -export type TSecretApprovalRequestsSecretsInsert = Omit; -export type TSecretApprovalRequestsSecretsUpdate = Partial>; +export type TSecretApprovalRequestsSecretsInsert = Omit< + TSecretApprovalRequestsSecrets, + TImmutableDBKeys +>; +export type TSecretApprovalRequestsSecretsUpdate = Partial< + Omit +>; diff --git a/backend/src/db/schemas/secret-approval-requests.ts b/backend/src/db/schemas/secret-approval-requests.ts index 7d5f2f443..8e3481cb0 100644 --- a/backend/src/db/schemas/secret-approval-requests.ts +++ b/backend/src/db/schemas/secret-approval-requests.ts @@ -11,16 +11,18 @@ export const SecretApprovalRequestsSchema = z.object({ id: z.string().uuid(), policyId: z.string().uuid(), hasMerged: z.boolean().default(false), - status: z.string().default('open'), + status: z.string().default("open"), conflicts: z.unknown().nullable().optional(), slug: z.string(), folderId: z.string().uuid(), statusChangeBy: z.string().uuid().nullable().optional(), committerId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretApprovalRequests = z.infer; export type TSecretApprovalRequestsInsert = Omit; -export type TSecretApprovalRequestsUpdate = Partial>; +export type TSecretApprovalRequestsUpdate = Partial< + Omit +>; diff --git a/backend/src/db/schemas/secret-blind-indexes.ts b/backend/src/db/schemas/secret-blind-indexes.ts index 17eacb473..fa919babd 100644 --- a/backend/src/db/schemas/secret-blind-indexes.ts +++ b/backend/src/db/schemas/secret-blind-indexes.ts @@ -12,11 +12,11 @@ export const SecretBlindIndexesSchema = z.object({ encryptedSaltCipherText: z.string(), saltIV: z.string(), saltTag: z.string(), - algorithm: z.string().default('aes-256-gcm'), - keyEncoding: z.string().default('utf8'), + algorithm: z.string().default("aes-256-gcm"), + keyEncoding: z.string().default("utf8"), projectId: z.string(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretBlindIndexes = z.infer; diff --git a/backend/src/db/schemas/secret-folder-versions.ts b/backend/src/db/schemas/secret-folder-versions.ts index 895f81ebc..8c550d065 100644 --- a/backend/src/db/schemas/secret-folder-versions.ts +++ b/backend/src/db/schemas/secret-folder-versions.ts @@ -14,7 +14,7 @@ export const SecretFolderVersionsSchema = z.object({ createdAt: z.date(), updatedAt: z.date(), envId: z.string().uuid(), - folderId: z.string().uuid(), + folderId: z.string().uuid() }); export type TSecretFolderVersions = z.infer; diff --git a/backend/src/db/schemas/secret-folders.ts b/backend/src/db/schemas/secret-folders.ts index aa437c753..648238b0a 100644 --- a/backend/src/db/schemas/secret-folders.ts +++ b/backend/src/db/schemas/secret-folders.ts @@ -14,7 +14,7 @@ export const SecretFoldersSchema = z.object({ createdAt: z.date(), updatedAt: z.date(), envId: z.string().uuid(), - parentId: z.string().uuid().nullable().optional(), + parentId: z.string().uuid().nullable().optional() }); export type TSecretFolders = z.infer; diff --git a/backend/src/db/schemas/secret-imports.ts b/backend/src/db/schemas/secret-imports.ts index 109d41ec2..9c1ee905f 100644 --- a/backend/src/db/schemas/secret-imports.ts +++ b/backend/src/db/schemas/secret-imports.ts @@ -15,7 +15,7 @@ export const SecretImportsSchema = z.object({ position: z.number(), createdAt: z.date(), updatedAt: z.date(), - folderId: z.string().uuid(), + folderId: z.string().uuid() }); export type TSecretImports = z.infer; diff --git a/backend/src/db/schemas/secret-rotation-outputs.ts b/backend/src/db/schemas/secret-rotation-outputs.ts index b98338c75..3b594365a 100644 --- a/backend/src/db/schemas/secret-rotation-outputs.ts +++ b/backend/src/db/schemas/secret-rotation-outputs.ts @@ -11,7 +11,7 @@ export const SecretRotationOutputsSchema = z.object({ id: z.string().uuid(), key: z.string(), secretId: z.string().uuid(), - rotationId: z.string().uuid(), + rotationId: z.string().uuid() }); export type TSecretRotationOutputs = z.infer; diff --git a/backend/src/db/schemas/secret-rotations.ts b/backend/src/db/schemas/secret-rotations.ts index 6e2bf6547..4c65712fa 100644 --- a/backend/src/db/schemas/secret-rotations.ts +++ b/backend/src/db/schemas/secret-rotations.ts @@ -22,7 +22,7 @@ export const SecretRotationsSchema = z.object({ keyEncoding: z.string().nullable().optional(), envId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretRotations = z.infer; diff --git a/backend/src/db/schemas/secret-scanning-git-risks.ts b/backend/src/db/schemas/secret-scanning-git-risks.ts index 0951d3ba5..b6a6fb142 100644 --- a/backend/src/db/schemas/secret-scanning-git-risks.ts +++ b/backend/src/db/schemas/secret-scanning-git-risks.ts @@ -38,9 +38,11 @@ export const SecretScanningGitRisksSchema = z.object({ status: z.string().nullable().optional(), orgId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretScanningGitRisks = z.infer; export type TSecretScanningGitRisksInsert = Omit; -export type TSecretScanningGitRisksUpdate = Partial>; +export type TSecretScanningGitRisksUpdate = Partial< + Omit +>; diff --git a/backend/src/db/schemas/secret-snapshot-folders.ts b/backend/src/db/schemas/secret-snapshot-folders.ts index 5f3b1a88c..acf11ab0a 100644 --- a/backend/src/db/schemas/secret-snapshot-folders.ts +++ b/backend/src/db/schemas/secret-snapshot-folders.ts @@ -13,7 +13,7 @@ export const SecretSnapshotFoldersSchema = z.object({ folderVersionId: z.string().uuid(), snapshotId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretSnapshotFolders = z.infer; diff --git a/backend/src/db/schemas/secret-snapshot-secrets.ts b/backend/src/db/schemas/secret-snapshot-secrets.ts index f8a69a695..6a83d1155 100644 --- a/backend/src/db/schemas/secret-snapshot-secrets.ts +++ b/backend/src/db/schemas/secret-snapshot-secrets.ts @@ -13,7 +13,7 @@ export const SecretSnapshotSecretsSchema = z.object({ secretVersionId: z.string().uuid(), snapshotId: z.string().uuid(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretSnapshotSecrets = z.infer; diff --git a/backend/src/db/schemas/secret-snapshots.ts b/backend/src/db/schemas/secret-snapshots.ts index ef9e0b7d0..ed255cb77 100644 --- a/backend/src/db/schemas/secret-snapshots.ts +++ b/backend/src/db/schemas/secret-snapshots.ts @@ -13,7 +13,7 @@ export const SecretSnapshotsSchema = z.object({ folderId: z.string().uuid(), parentFolderId: z.string().uuid().nullable().optional(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSecretSnapshots = z.infer; diff --git a/backend/src/db/schemas/secret-tag-junction.ts b/backend/src/db/schemas/secret-tag-junction.ts index 467ef7b15..1d25574c5 100644 --- a/backend/src/db/schemas/secret-tag-junction.ts +++ b/backend/src/db/schemas/secret-tag-junction.ts @@ -10,7 +10,7 @@ import { TImmutableDBKeys } from "./models"; export const SecretTagJunctionSchema = z.object({ id: z.string().uuid(), secretsId: z.string().uuid(), - secret_tagsId: z.string().uuid(), + secret_tagsId: z.string().uuid() }); export type TSecretTagJunction = z.infer; diff --git a/backend/src/db/schemas/secret-tags.ts b/backend/src/db/schemas/secret-tags.ts index 78f03dedd..622c29bd3 100644 --- a/backend/src/db/schemas/secret-tags.ts +++ b/backend/src/db/schemas/secret-tags.ts @@ -15,7 +15,7 @@ export const SecretTagsSchema = z.object({ createdAt: z.date(), updatedAt: z.date(), createdBy: z.string().uuid().nullable().optional(), - projectId: z.string(), + projectId: z.string() }); export type TSecretTags = z.infer; diff --git a/backend/src/db/schemas/secret-version-tag-junction.ts b/backend/src/db/schemas/secret-version-tag-junction.ts index 11b3f0032..95d4db0bb 100644 --- a/backend/src/db/schemas/secret-version-tag-junction.ts +++ b/backend/src/db/schemas/secret-version-tag-junction.ts @@ -10,9 +10,11 @@ import { TImmutableDBKeys } from "./models"; export const SecretVersionTagJunctionSchema = z.object({ id: z.string().uuid(), secret_versionsId: z.string().uuid(), - secret_tagsId: z.string().uuid(), + secret_tagsId: z.string().uuid() }); export type TSecretVersionTagJunction = z.infer; export type TSecretVersionTagJunctionInsert = Omit; -export type TSecretVersionTagJunctionUpdate = Partial>; +export type TSecretVersionTagJunctionUpdate = Partial< + Omit +>; diff --git a/backend/src/db/schemas/service-tokens.ts b/backend/src/db/schemas/service-tokens.ts index c12e28432..24720f3e4 100644 --- a/backend/src/db/schemas/service-tokens.ts +++ b/backend/src/db/schemas/service-tokens.ts @@ -21,7 +21,7 @@ export const ServiceTokensSchema = z.object({ createdAt: z.date(), updatedAt: z.date(), createdBy: z.string(), - projectId: z.string(), + projectId: z.string() }); export type TServiceTokens = z.infer; diff --git a/backend/src/db/schemas/super-admin.ts b/backend/src/db/schemas/super-admin.ts index f998cf325..13bf45e7b 100644 --- a/backend/src/db/schemas/super-admin.ts +++ b/backend/src/db/schemas/super-admin.ts @@ -12,7 +12,7 @@ export const SuperAdminSchema = z.object({ initialized: z.boolean().default(false).nullable().optional(), allowSignUp: z.boolean().default(true).nullable().optional(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TSuperAdmin = z.infer; diff --git a/backend/src/db/schemas/trusted-ips.ts b/backend/src/db/schemas/trusted-ips.ts index c3311340d..6d9018db3 100644 --- a/backend/src/db/schemas/trusted-ips.ts +++ b/backend/src/db/schemas/trusted-ips.ts @@ -16,7 +16,7 @@ export const TrustedIpsSchema = z.object({ comment: z.string().nullable().optional(), projectId: z.string(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TTrustedIps = z.infer; diff --git a/backend/src/db/schemas/user-actions.ts b/backend/src/db/schemas/user-actions.ts index a3a07d699..eaa03ba98 100644 --- a/backend/src/db/schemas/user-actions.ts +++ b/backend/src/db/schemas/user-actions.ts @@ -12,7 +12,7 @@ export const UserActionsSchema = z.object({ action: z.string(), createdAt: z.date(), updatedAt: z.date(), - userId: z.string().uuid(), + userId: z.string().uuid() }); export type TUserActions = z.infer; diff --git a/backend/src/db/schemas/user-encryption-keys.ts b/backend/src/db/schemas/user-encryption-keys.ts index 938b93aaf..8f35b09fe 100644 --- a/backend/src/db/schemas/user-encryption-keys.ts +++ b/backend/src/db/schemas/user-encryption-keys.ts @@ -21,7 +21,7 @@ export const UserEncryptionKeysSchema = z.object({ tag: z.string(), salt: z.string(), verifier: z.string(), - userId: z.string().uuid(), + userId: z.string().uuid() }); export type TUserEncryptionKeys = z.infer; diff --git a/backend/src/db/schemas/users.ts b/backend/src/db/schemas/users.ts index b9689883d..4a29de510 100644 --- a/backend/src/db/schemas/users.ts +++ b/backend/src/db/schemas/users.ts @@ -19,7 +19,7 @@ export const UsersSchema = z.object({ mfaMethods: z.string().array().nullable().optional(), devices: z.unknown().nullable().optional(), createdAt: z.date(), - updatedAt: z.date(), + updatedAt: z.date() }); export type TUsers = z.infer; diff --git a/backend/src/db/schemas/webhooks.ts b/backend/src/db/schemas/webhooks.ts index 2b7e36cab..7abfb3772 100644 --- a/backend/src/db/schemas/webhooks.ts +++ b/backend/src/db/schemas/webhooks.ts @@ -9,7 +9,7 @@ import { TImmutableDBKeys } from "./models"; export const WebhooksSchema = z.object({ id: z.string().uuid(), - secretPath: z.string().default('/'), + secretPath: z.string().default("/"), url: z.string(), lastStatus: z.string().nullable().optional(), lastRunErrorMessage: z.string().nullable().optional(), @@ -21,7 +21,7 @@ export const WebhooksSchema = z.object({ keyEncoding: z.string().nullable().optional(), createdAt: z.date(), updatedAt: z.date(), - envId: z.string().uuid(), + envId: z.string().uuid() }); export type TWebhooks = z.infer; diff --git a/backend/src/db/seeds/1-user.ts b/backend/src/db/seeds/1-user.ts index 7855ebc78..ca0042a98 100644 --- a/backend/src/db/seeds/1-user.ts +++ b/backend/src/db/seeds/1-user.ts @@ -14,7 +14,7 @@ export async function seed(knex: Knex): Promise { const [user] = await knex(TableName.Users) .insert([ { - // @ts-ignore to calculate predefined + // @ts-expect-error exluded type id needs to be inserted here to keep it testable id: seedData1.id, email: seedData1.email, superAdmin: true, @@ -48,7 +48,7 @@ export async function seed(knex: Knex): Promise { ]); await knex(TableName.AuthTokenSession).insert({ - // @ts-ignore + // @ts-expect-error exluded type id needs to be inserted here to keep it testable id: seedData1.token.id, userId: seedData1.id, ip: "151.196.220.213", diff --git a/backend/src/db/seeds/2-org.ts b/backend/src/db/seeds/2-org.ts index ec7e9dd43..a9c3ec3c7 100644 --- a/backend/src/db/seeds/2-org.ts +++ b/backend/src/db/seeds/2-org.ts @@ -14,7 +14,7 @@ export async function seed(knex: Knex): Promise { const [org] = await knex(TableName.Organization) .insert([ { - // @ts-ignore because we need that id for api calls + // @ts-expect-error exluded type id needs to be inserted here to keep it testable id: seedData1.organization.id, name: "infisical", slug: "infisical", diff --git a/backend/src/db/seeds/3-project.ts b/backend/src/db/seeds/3-project.ts index 48d4df5c1..26f4dfced 100644 --- a/backend/src/db/seeds/3-project.ts +++ b/backend/src/db/seeds/3-project.ts @@ -20,7 +20,7 @@ export async function seed(knex: Knex): Promise { name: seedData1.project.name, orgId: seedData1.organization.id, slug: "first-project", - // @ts-ignore pre calc id + // @ts-expect-error exluded type id needs to be inserted here to keep it testable id: seedData1.project.id }) .returning("*"); diff --git a/backend/src/ee/routes/v1/license-router.ts b/backend/src/ee/routes/v1/license-router.ts index 36c3a571d..e560fc842 100644 --- a/backend/src/ee/routes/v1/license-router.ts +++ b/backend/src/ee/routes/v1/license-router.ts @@ -1,3 +1,6 @@ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +// TODO(akhilmhdh): Fix this when licence service gets it type import { z } from "zod"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; diff --git a/backend/src/ee/routes/v1/org-role-router.ts b/backend/src/ee/routes/v1/org-role-router.ts index 79e392880..5b80f298d 100644 --- a/backend/src/ee/routes/v1/org-role-router.ts +++ b/backend/src/ee/routes/v1/org-role-router.ts @@ -26,7 +26,6 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const role = await server.services.orgRole.createRole( req.permission.id, req.params.organizationId, @@ -58,7 +57,6 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const role = await server.services.orgRole.updateRole( req.permission.id, req.params.organizationId, @@ -85,7 +83,6 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const role = await server.services.orgRole.deleteRole( req.permission.id, req.params.organizationId, @@ -114,7 +111,6 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const roles = await server.services.orgRole.listRoles( req.permission.id, req.params.organizationId @@ -139,7 +135,6 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const { permissions, membership } = await server.services.orgRole.getUserPermission( req.permission.id, req.params.organizationId diff --git a/backend/src/ee/routes/v1/project-role-router.ts b/backend/src/ee/routes/v1/project-role-router.ts index 622762bca..86f2242e2 100644 --- a/backend/src/ee/routes/v1/project-role-router.ts +++ b/backend/src/ee/routes/v1/project-role-router.ts @@ -141,7 +141,6 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const { permissions, membership } = await server.services.projectRole.getUserPermission( req.permission.id, req.params.projectId diff --git a/backend/src/ee/routes/v1/saml-router.ts b/backend/src/ee/routes/v1/saml-router.ts index 96ee2408d..7f08abd35 100644 --- a/backend/src/ee/routes/v1/saml-router.ts +++ b/backend/src/ee/routes/v1/saml-router.ts @@ -1,3 +1,11 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +// All the any rules are disabled because passport typesense with fastify is really poor + import { Authenticator } from "@fastify/passport"; import fastifySession from "@fastify/session"; import { MultiSamlStrategy } from "@node-saml/passport-saml"; @@ -33,6 +41,7 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => { new MultiSamlStrategy( { passReqToCallback: true, + // eslint-disable-next-line getSamlOptions: async (req, done) => { try { const { ssoIdentifier } = req.params; @@ -67,6 +76,7 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => { } } }, + // eslint-disable-next-line async (req, profile, cb) => { try { const serverCfg = getServerCfg(); diff --git a/backend/src/ee/routes/v1/secret-approval-policy-router.ts b/backend/src/ee/routes/v1/secret-approval-policy-router.ts index 49d2b95ad..eb3da2bb2 100644 --- a/backend/src/ee/routes/v1/secret-approval-policy-router.ts +++ b/backend/src/ee/routes/v1/secret-approval-policy-router.ts @@ -111,17 +111,18 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi }), response: { 200: z.object({ - approvals: sapPubSchema.merge(z.object({approvers:z.string().array()})).array() + approvals: sapPubSchema.merge(z.object({ approvers: z.string().array() })).array() }) } }, onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { - const approvals = await server.services.secretApprovalPolicy.getSecretApprovalPolicyByProjectId({ - actor: req.permission.type, - actorId: req.permission.id, - projectId: req.query.workspaceId - }); + const approvals = + await server.services.secretApprovalPolicy.getSecretApprovalPolicyByProjectId({ + actor: req.permission.type, + actorId: req.permission.id, + projectId: req.query.workspaceId + }); return { approvals }; } }); @@ -137,7 +138,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi }), response: { 200: z.object({ - policy: sapPubSchema.merge(z.object({approvers:z.string().array()})).optional() + policy: sapPubSchema.merge(z.object({ approvers: z.string().array() })).optional() }) } }, diff --git a/backend/src/ee/routes/v1/secret-approval-request-router.ts b/backend/src/ee/routes/v1/secret-approval-request-router.ts index a745a9b04..056da4839 100644 --- a/backend/src/ee/routes/v1/secret-approval-request-router.ts +++ b/backend/src/ee/routes/v1/secret-approval-request-router.ts @@ -174,11 +174,13 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv ...req.auditLogInfo, event: { type: isClosing ? EventType.SECRET_APPROVAL_CLOSED : EventType.SECRET_APPROVAL_REOPENED, + // eslint-disable-next-line metadata: { [isClosing ? ("closedBy" as const) : ("reopenedBy" as const)]: approval.statusChangeBy as string, secretApprovalRequestId: approval.id, secretApprovalRequestSlug: approval.slug + // eslint-disable-next-line } as any // akhilmhdh: had to apply any to avoid ts issue with this } diff --git a/backend/src/ee/services/audit-log/audit-log-dal.ts b/backend/src/ee/services/audit-log/audit-log-dal.ts index ec5f6ab3d..6606bf3aa 100644 --- a/backend/src/ee/services/audit-log/audit-log-dal.ts +++ b/backend/src/ee/services/audit-log/audit-log-dal.ts @@ -48,10 +48,10 @@ export const auditLogDALFactory = (db: TDbClient) => { .limit(limit) .offset(offset); if (startDate) { - sqlQuery.where("createdAt", ">=", startDate); + void sqlQuery.where("createdAt", ">=", startDate); } if (endDate) { - sqlQuery.where("createdAt", "<=", endDate); + void sqlQuery.where("createdAt", "<=", endDate); } const docs = await sqlQuery; return docs; diff --git a/backend/src/ee/services/license/licence-fns.ts b/backend/src/ee/services/license/licence-fns.ts index ca69b7d0e..e6fa98cb8 100644 --- a/backend/src/ee/services/license/licence-fns.ts +++ b/backend/src/ee/services/license/licence-fns.ts @@ -39,7 +39,7 @@ export const setupLicenceRequestWithStore = ( let token: string; const licenceReq = axios.create({ baseURL, - timeout: 35 * 1000, + timeout: 35 * 1000 // signal: AbortSignal.timeout(60 * 1000) }); @@ -47,7 +47,7 @@ export const setupLicenceRequestWithStore = ( const appCfg = getConfig(); const { data: { token: authToken } - } = await request.post( + } = await request.post<{ token: string }>( refreshUrl, {}, { @@ -75,18 +75,18 @@ export const setupLicenceRequestWithStore = ( licenceReq.interceptors.response.use( (response) => response, async (err) => { - const originalRequest = err.config; + const originalRequest = (err as AxiosError).config; // eslint-disable-next-line - if ((err as AxiosError)?.response?.status === 401 && !originalRequest._retry) { + if ((err as AxiosError)?.response?.status === 401 && !(originalRequest as any)._retry) { // eslint-disable-next-line - originalRequest._retry = true; + (originalRequest as any)._retry = true; // injected // refresh await refreshLicence(); licenceReq.defaults.headers.common.Authorization = `Bearer ${token}`; - return licenceReq(originalRequest); + return licenceReq(originalRequest!); } return Promise.reject(err); diff --git a/backend/src/ee/services/license/license-dal.ts b/backend/src/ee/services/license/license-dal.ts index 208cb6f9b..4e70dfb5a 100644 --- a/backend/src/ee/services/license/license-dal.ts +++ b/backend/src/ee/services/license/license-dal.ts @@ -13,7 +13,7 @@ export const licenseDALFactory = (db: TDbClient) => { .where({ status: OrgMembershipStatus.Accepted }) .andWhere((bd) => { if (orgId) { - bd.where({ orgId }); + void bd.where({ orgId }); } }) .count(); diff --git a/backend/src/ee/services/license/license-service.ts b/backend/src/ee/services/license/license-service.ts index 6ed9230be..00e654875 100644 --- a/backend/src/ee/services/license/license-service.ts +++ b/backend/src/ee/services/license/license-service.ts @@ -1,3 +1,9 @@ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +// eslint-disable @typescript-eslint/no-unsafe-assignment + +// TODO(akhilmhdh): With tony find out the api structure and fill it here + import { ForbiddenError } from "@casl/ability"; import NodeCache from "node-cache"; @@ -92,7 +98,7 @@ export const licenseServiceFactory = ({ // else it would reach catch statement isValidLicense = true; } catch (error) { - logger.error(`init-license: encountered an error when init license [error=${error}]`); + logger.error(`init-license: encountered an error when init license [error]`, error); } }; @@ -119,7 +125,10 @@ export const licenseServiceFactory = ({ return currentPlan; } } catch (error) { - logger.error(`getPlan: encountered an error when fetching pan [orgId=${orgId}] [projectId=${projectId}] [error=${error}]`); + logger.error( + `getPlan: encountered an error when fetching pan [orgId=${orgId}] [projectId=${projectId}] [error]`, + error + ); return onPremFeatures; } return onPremFeatures; @@ -136,7 +145,7 @@ export const licenseServiceFactory = ({ if (instanceType === InstanceType.Cloud) { const { data: { customerId } - } = await licenseServerCloudApi.request.post( + } = await licenseServerCloudApi.request.post<{ customerId: string }>( "/api/license-server/v1/customers", { email, diff --git a/backend/src/ee/services/permission/project-permission.ts b/backend/src/ee/services/permission/project-permission.ts index f3fb67705..5245c26e4 100644 --- a/backend/src/ee/services/permission/project-permission.ts +++ b/backend/src/ee/services/permission/project-permission.ts @@ -239,17 +239,29 @@ export const buildServiceTokenProjectPermission = ( const { can, build } = new AbilityBuilder>(createMongoAbility); scopes.forEach(({ secretPath, environment }) => { if (canWrite) { - // TODO: @Akhi - // @ts-expect-error type - can(ProjectPermissionActions.Edit, ProjectPermissionSub.Secrets, { secretPath: { $glob: secretPath }, environment }); - // @ts-expect-error type - can(ProjectPermissionActions.Create, ProjectPermissionSub.Secrets, { secretPath: { $glob: secretPath }, environment }); - // @ts-expect-error type - can(ProjectPermissionActions.Delete, ProjectPermissionSub.Secrets, {secretPath: { $glob: secretPath }, environment }); + // TODO: @Akhi + // @ts-expect-error type + can(ProjectPermissionActions.Edit, ProjectPermissionSub.Secrets, { + secretPath: { $glob: secretPath }, + environment + }); + // @ts-expect-error type + can(ProjectPermissionActions.Create, ProjectPermissionSub.Secrets, { + secretPath: { $glob: secretPath }, + environment + }); + // @ts-expect-error type + can(ProjectPermissionActions.Delete, ProjectPermissionSub.Secrets, { + secretPath: { $glob: secretPath }, + environment + }); } if (canRead) { - // @ts-expect-error type - can(ProjectPermissionActions.Read, ProjectPermissionSub.Secrets, { secretPath: { $glob: secretPath }, environment }); + // @ts-expect-error type + can(ProjectPermissionActions.Read, ProjectPermissionSub.Secrets, { + secretPath: { $glob: secretPath }, + environment + }); } }); @@ -258,6 +270,8 @@ export const buildServiceTokenProjectPermission = ( export const projectNoAccessPermissions = buildNoAccessProjectPermission(); +/* eslint-disable */ + /** * Extracts and formats permissions from a CASL Ability object or a raw permission set. * @param ability @@ -287,3 +301,5 @@ export const isAtLeastAsPrivilegedWorkspace = ( return set1.size >= set2.size; }; + +/* eslint-enable */ diff --git a/backend/src/ee/services/saml-config/saml-config-service.ts b/backend/src/ee/services/saml-config/saml-config-service.ts index ad6a34a37..c9d0989e9 100644 --- a/backend/src/ee/services/saml-config/saml-config-service.ts +++ b/backend/src/ee/services/saml-config/saml-config-service.ts @@ -239,9 +239,9 @@ export const samlConfigServiceFactory = ({ "64f23239a5d4ed17f1e544c4": "9256337f-e3da-43d7-8266-39c9276e8426", "65348e49db355e6e4782571f": "b8a227c7-843e-410e-8982-b4976a599b69", "657a219fc8a80c2eff97eb38": "fcab1573-ae7f-4fcf-9645-646207acf035" - }; + }; - const id = UUIDToMongoId[dto.id] ?? dto.id + const id = UUIDToMongoId[dto.id] ?? dto.id; ssoConfig = await samlConfigDAL.findById(id); } @@ -252,7 +252,7 @@ export const samlConfigServiceFactory = ({ const { permission } = await permissionService.getOrgPermission( dto.actor, dto.actorId, - ssoConfig!.orgId + ssoConfig.orgId ); ForbiddenError.from(permission).throwUnlessCan( OrgPermissionActions.Read, @@ -400,7 +400,7 @@ export const samlConfigServiceFactory = ({ isUserCompleted, ...(relayState ? { - callbackPort: JSON.parse(relayState).callbackPort as string + callbackPort: (JSON.parse(relayState) as { callbackPort: string }).callbackPort } : {}) }, diff --git a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-dal.ts b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-dal.ts index ea895262d..b2cc41884 100644 --- a/backend/src/ee/services/secret-approval-policy/secret-approval-policy-dal.ts +++ b/backend/src/ee/services/secret-approval-policy/secret-approval-policy-dal.ts @@ -18,6 +18,7 @@ export const secretApprovalPolicyDALFactory = (db: TDbClient) => { const sapFindQuery = (tx: Knex, filter: TFindFilter) => tx(TableName.SecretApprovalPolicy) + // eslint-disable-next-line .where(buildFindFilter(filter)) .join( TableName.Environment, diff --git a/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts b/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts index cda07eff9..f1a4f3bb0 100644 --- a/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts +++ b/backend/src/ee/services/secret-approval-request/secret-approval-request-dal.ts @@ -1,7 +1,12 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { SecretApprovalRequestsSchema, TableName, TSecretApprovalRequests } from "@app/db/schemas"; +import { + SecretApprovalRequestsSchema, + TableName, + TSecretApprovalRequests, + TSecretApprovalRequestsSecrets +} from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify, @@ -125,10 +130,11 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { `${TableName.SecretApprovalPolicyApprover}.policyId` ) .where({ projectId }) - .andWhere((bd) => - bd - .where(`${TableName.SecretApprovalPolicyApprover}.approverId`, membershipId) - .orWhere(`${TableName.SecretApprovalRequest}.committerId`, membershipId) + .andWhere( + (bd) => + void bd + .where(`${TableName.SecretApprovalPolicyApprover}.approverId`, membershipId) + .orWhere(`${TableName.SecretApprovalRequest}.committerId`, membershipId) ) .select("status", `${TableName.SecretApprovalRequest}.id`) .groupBy(`${TableName.SecretApprovalRequest}.id`, "status") @@ -141,11 +147,13 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { return { open: parseInt( - (docs.find(({ status }) => status === RequestState.Open)?.count as string) || "0", + (docs.find(({ status }) => status === RequestState.Open) as { count: string })?.count || + "0", 10 ), closed: parseInt( - (docs.find(({ status }) => status === RequestState.Closed)?.count as string) || "0", + (docs.find(({ status }) => status === RequestState.Closed) as { count: string })?.count || + "0", 10 ) }; @@ -195,7 +203,7 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { `${TableName.SecretApprovalRequest}.id`, `${TableName.SecretApprovalRequestReviewer}.requestId` ) - .leftJoin( + .leftJoin( TableName.SecretApprovalRequestSecret, `${TableName.SecretApprovalRequestSecret}.requestId`, `${TableName.SecretApprovalRequest}.id` @@ -208,10 +216,11 @@ export const secretApprovalRequestDALFactory = (db: TDbClient) => { committerId: committer }) ) - .andWhere((bd) => - bd - .where(`${TableName.SecretApprovalPolicyApprover}.approverId`, membershipId) - .orWhere(`${TableName.SecretApprovalRequest}.committerId`, membershipId) + .andWhere( + (bd) => + void bd + .where(`${TableName.SecretApprovalPolicyApprover}.approverId`, membershipId) + .orWhere(`${TableName.SecretApprovalRequest}.committerId`, membershipId) ) .select(selectAllTableCols(TableName.SecretApprovalRequest)) .select( diff --git a/backend/src/ee/services/secret-approval-request/secret-approval-request-secret-dal.ts b/backend/src/ee/services/secret-approval-request/secret-approval-request-secret-dal.ts index a0d25ae65..cc78b3dff 100644 --- a/backend/src/ee/services/secret-approval-request/secret-approval-request-secret-dal.ts +++ b/backend/src/ee/services/secret-approval-request/secret-approval-request-secret-dal.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { SecretApprovalRequestsSecretsSchema, TableName } from "@app/db/schemas"; +import { SecretApprovalRequestsSecretsSchema, TableName, TSecretTags } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex"; @@ -45,7 +45,7 @@ export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => { `${TableName.SecretVersionTag}.${TableName.SecretVersion}Id`, `${TableName.SecretVersion}.id` ) - .leftJoin( + .leftJoin( db.ref(TableName.SecretTag).as("secVerTag"), `${TableName.SecretVersionTag}.${TableName.SecretTag}Id`, db.ref("id").withSchema("secVerTag") @@ -192,9 +192,13 @@ export const secretApprovalRequestSecretDALFactory = (db: TDbClient) => { secVerTagSlug: slug, secVerTagColor: color }) => ({ + // eslint-disable-next-line id, + // eslint-disable-next-line name, + // eslint-disable-next-line slug, + // eslint-disable-next-line color }) } diff --git a/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts b/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts index bcd96e090..5ed14f490 100644 --- a/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts +++ b/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue-fn.ts @@ -1,3 +1,8 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable no-param-reassign */ import axios from "axios"; import jmespath from "jmespath"; @@ -37,7 +42,7 @@ export const interpolate = (data: any, getValue: (key: string) => unknown) => { if ((data as { ref: string })?.ref) return getValue((data as { ref: string }).ref); const temp = data as Record; // for converting ts object to record type Object.keys(temp).forEach((key) => { - temp[key as keyof typeof temp] = interpolate(data[key as keyof typeof temp], getValue); + temp[key] = interpolate(data[key], getValue); }); } return data; diff --git a/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue.ts b/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue.ts index 5c4dc5e30..978f9ea71 100644 --- a/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue.ts +++ b/backend/src/ee/services/secret-rotation/secret-rotation-queue/secret-rotation-queue.ts @@ -6,6 +6,7 @@ import { infisicalSymmetricEncypt } from "@app/lib/crypto/encryption"; import { daysToMillisecond, secondsToMillis } from "@app/lib/dates"; +import { BadRequestError } from "@app/lib/errors"; import { logger } from "@app/lib/logger"; import { alphaNumericNanoId } from "@app/lib/nanoid"; import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue"; @@ -34,7 +35,6 @@ import { TSecretRotationDbFn, TSecretRotationEncData } from "./secret-rotation-queue-types"; -import { BadRequestError } from "@app/lib/errors"; export type TSecretRotationQueueFactory = ReturnType; @@ -70,7 +70,7 @@ export const secretRotationQueueFactory = ({ }: TSecretRotationQueueFactoryDep) => { const addToQueue = async (rotationId: string, interval: number) => { const appCfg = getConfig(); - queue.queue( + await queue.queue( QueueName.SecretRotation, QueueJobs.SecretRotation, { rotationId }, @@ -265,7 +265,7 @@ export const secretRotationQueueFactory = ({ return { ...el, secretId: id, - secretBlindIndex: el.secretBlindIndex as string + secretBlindIndex: el.secretBlindIndex }; }), tx @@ -288,7 +288,7 @@ export const secretRotationQueueFactory = ({ logger.error(error); if (error instanceof DisableRotationErrors) { if (job.id) { - queue.stopRepeatableJobByJobId(QueueName.SecretRotation, job.id); + await queue.stopRepeatableJobByJobId(QueueName.SecretRotation, job.id); } } diff --git a/backend/src/ee/services/secret-scanning/git-app-dal.ts b/backend/src/ee/services/secret-scanning/git-app-dal.ts index 8a3ec706e..2a7014180 100644 --- a/backend/src/ee/services/secret-scanning/git-app-dal.ts +++ b/backend/src/ee/services/secret-scanning/git-app-dal.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName,TGitAppOrgInsert } from "@app/db/schemas"; +import { TableName, TGitAppOrgInsert } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify } from "@app/lib/knex"; diff --git a/backend/src/ee/services/secret-scanning/git-app-install-session-dal.ts b/backend/src/ee/services/secret-scanning/git-app-install-session-dal.ts index 9956d88ec..11f8eb53c 100644 --- a/backend/src/ee/services/secret-scanning/git-app-install-session-dal.ts +++ b/backend/src/ee/services/secret-scanning/git-app-install-session-dal.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName,TGitAppInstallSessionsInsert } from "@app/db/schemas"; +import { TableName, TGitAppInstallSessionsInsert } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify } from "@app/lib/knex"; diff --git a/backend/src/ee/services/secret-scanning/secret-scanning-dal.ts b/backend/src/ee/services/secret-scanning/secret-scanning-dal.ts index 4b5dcb378..98260a0dc 100644 --- a/backend/src/ee/services/secret-scanning/secret-scanning-dal.ts +++ b/backend/src/ee/services/secret-scanning/secret-scanning-dal.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName,TSecretScanningGitRisksInsert } from "@app/db/schemas"; +import { TableName, TSecretScanningGitRisksInsert } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify } from "@app/lib/knex"; diff --git a/backend/src/ee/services/secret-scanning/secret-scanning-queue/secret-scanning-fns.ts b/backend/src/ee/services/secret-scanning/secret-scanning-queue/secret-scanning-fns.ts index b444cf56b..2e74a1caf 100644 --- a/backend/src/ee/services/secret-scanning/secret-scanning-queue/secret-scanning-fns.ts +++ b/backend/src/ee/services/secret-scanning/secret-scanning-queue/secret-scanning-fns.ts @@ -1,3 +1,4 @@ +import { Octokit } from "@octokit/rest"; import { exec } from "child_process"; import { mkdir, readFile, rm, writeFile } from "fs"; import { tmpdir } from "os"; @@ -11,7 +12,7 @@ export function createTempFolder(): Promise { const tempFolderName = Math.random().toString(36).substring(2); const tempFolderPath = join(tempDir, tempFolderName); - mkdir(tempFolderPath, (err: any) => { + mkdir(tempFolderPath, (err) => { if (err) { reject(err); } else { @@ -115,7 +116,7 @@ export function convertKeysToLowercase(obj: T): T { } export async function scanFullRepoContentAndGetFindings( - octokit: any, + octokit: Octokit, installationId: string, repositoryFullName: string ): Promise { @@ -125,11 +126,13 @@ export async function scanFullRepoContentAndGetFindings( try { const { data: { token } - } = await octokit.apps.createInstallationAccessToken({ installation_id: installationId }); + } = await octokit.apps.createInstallationAccessToken({ + installation_id: Number(installationId) + }); await cloneRepo(token, repositoryFullName, repoPath); await runInfisicalScanOnRepo(repoPath, findingsPath); const findingsData = await readFindingsFile(findingsPath); - return JSON.parse(findingsData); + return JSON.parse(findingsData) as SecretMatch[]; } finally { await deleteTempFolder(tempFolder); } @@ -144,7 +147,7 @@ export async function scanContentAndGetFindings(textContent: string): Promise { if (!Object.keys(allFindingsByFingerprint).length) return; - secretScanningDAL.upsert( + await secretScanningDAL.upsert( Object.keys(allFindingsByFingerprint).map((key) => ({ installationId, email: allFindingsByFingerprint[key].Email, @@ -186,7 +186,9 @@ export const secretScanningQueueFactory = ({ }); const findings = await scanFullRepoContentAndGetFindings( - octokit, + // this is because of collision of octokit in probot and github + // eslint-disable-next-line + octokit as any, installationId, repository.fullName ); diff --git a/backend/src/ee/services/secret-scanning/secret-scanning-service.ts b/backend/src/ee/services/secret-scanning/secret-scanning-service.ts index 63aae869f..5410d0eec 100644 --- a/backend/src/ee/services/secret-scanning/secret-scanning-service.ts +++ b/backend/src/ee/services/secret-scanning/secret-scanning-service.ts @@ -170,9 +170,7 @@ export const secretScanningServiceFactory = ({ await secretScanningDAL.transaction(async (tx) => { if (repositoryIds.length) { await Promise.all( - repositoryIds.map((repoId) => - secretScanningDAL.delete({ repositoryId: repoId }, tx) - ) + repositoryIds.map((repoId) => secretScanningDAL.delete({ repositoryId: repoId }, tx)) ); } await gitAppOrgDAL.delete({ installationId }, tx); diff --git a/backend/src/ee/services/secret-snapshot/snapshot-dal.ts b/backend/src/ee/services/secret-snapshot/snapshot-dal.ts index 66c72ca53..912e9273a 100644 --- a/backend/src/ee/services/secret-snapshot/snapshot-dal.ts +++ b/backend/src/ee/services/secret-snapshot/snapshot-dal.ts @@ -162,7 +162,8 @@ export const snapshotDALFactory = (db: TDbClient) => { try { const data = await (tx || db) .withRecursive("parent", (qb) => { - qb.from(TableName.Snapshot) + void qb + .from(TableName.Snapshot) .leftJoin( TableName.SnapshotFolder, `${TableName.SnapshotFolder}.snapshotId`, @@ -180,35 +181,36 @@ export const snapshotDALFactory = (db: TDbClient) => { db.ref("folderId").withSchema(TableName.SecretFolderVersion).as("folderVerId") ) .where(`${TableName.Snapshot}.id`, snapshotId) - .union((cb) => - cb - .select(selectAllTableCols(TableName.Snapshot)) - .select({ depth: db.raw("parent.depth + 1") }) - .select( - db.ref("name").withSchema(TableName.SecretFolderVersion).as("folderVerName"), - db.ref("folderId").withSchema(TableName.SecretFolderVersion).as("folderVerId") - ) - .from(TableName.Snapshot) - .join( - db(TableName.Snapshot) - .groupBy("folderId") - .max("createdAt") - .select("folderId") - .as("latestVersion"), - `${TableName.Snapshot}.createdAt`, - "latestVersion.max" - ) - .leftJoin( - TableName.SnapshotFolder, - `${TableName.SnapshotFolder}.snapshotId`, - `${TableName.Snapshot}.id` - ) - .leftJoin( - TableName.SecretFolderVersion, - `${TableName.SnapshotFolder}.folderVersionId`, - `${TableName.SecretFolderVersion}.id` - ) - .join("parent", "parent.folderVerId", `${TableName.Snapshot}.folderId`) + .union( + (cb) => + void cb + .select(selectAllTableCols(TableName.Snapshot)) + .select({ depth: db.raw("parent.depth + 1") }) + .select( + db.ref("name").withSchema(TableName.SecretFolderVersion).as("folderVerName"), + db.ref("folderId").withSchema(TableName.SecretFolderVersion).as("folderVerId") + ) + .from(TableName.Snapshot) + .join( + db(TableName.Snapshot) + .groupBy("folderId") + .max("createdAt") + .select("folderId") + .as("latestVersion"), + `${TableName.Snapshot}.createdAt`, + "latestVersion.max" + ) + .leftJoin( + TableName.SnapshotFolder, + `${TableName.SnapshotFolder}.snapshotId`, + `${TableName.Snapshot}.id` + ) + .leftJoin( + TableName.SecretFolderVersion, + `${TableName.SnapshotFolder}.folderVersionId`, + `${TableName.SecretFolderVersion}.id` + ) + .join("parent", "parent.folderVerId", `${TableName.Snapshot}.folderId`) ); }) .orderBy("depth", "asc") @@ -285,7 +287,7 @@ export const snapshotDALFactory = (db: TDbClient) => { label: "secretVersions" as const, mapper: (el) => ({ ...SecretVersionsSchema.parse(el), - latestSecretVersion: el.latestSecretVersion + latestSecretVersion: el.latestSecretVersion as number }), childrenMapper: [ { @@ -307,7 +309,7 @@ export const snapshotDALFactory = (db: TDbClient) => { mapper: ({ folderVerId: id, folderVerName: name, latestFolderVersion }) => ({ id, name, - latestFolderVersion + latestFolderVersion: latestFolderVersion as number }) } ] diff --git a/backend/src/lib/casl/index.ts b/backend/src/lib/casl/index.ts index 1e853cc4d..c0547a6bb 100644 --- a/backend/src/lib/casl/index.ts +++ b/backend/src/lib/casl/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ import { buildMongoQueryMatcher, MongoAbility } from "@casl/ability"; import { FieldCondition, FieldInstruction, JsInterpreter } from "@ucast/mongo2js"; import picomatch from "picomatch"; @@ -12,7 +13,7 @@ const $glob: FieldInstruction = { }; const glob: JsInterpreter> = (node, object, context) => { - const secretPath = context.get(object, node.field); + const secretPath = context.get(object, node.field) as string; const permissionSecretGlobPath = node.value; return picomatch.isMatch(secretPath, permissionSecretGlobPath, { strictSlashes: false }); }; @@ -23,7 +24,9 @@ export const conditionsMatcher = buildMongoQueryMatcher({ $glob }, { glob }); * Extracts and formats permissions from a CASL Ability object or a raw permission set. */ const extractPermissions = (ability: MongoAbility) => - ability.rules.map((permission) => `${permission.action}_${permission.subject}`); + ability.rules.map( + (permission) => `${permission.action as string}_${permission.subject as string}` + ); /** * Compares two sets of permissions to determine if the first set is at least as privileged as the second set. diff --git a/backend/src/lib/config/env.ts b/backend/src/lib/config/env.ts index 25d985f41..406d9e297 100644 --- a/backend/src/lib/config/env.ts +++ b/backend/src/lib/config/env.ts @@ -56,7 +56,12 @@ const envSchema = z CLIENT_SECRET_GITHUB_LOGIN: zpStr(z.string().optional()), CLIENT_ID_GITLAB_LOGIN: zpStr(z.string().optional()), CLIENT_SECRET_GITLAB_LOGIN: zpStr(z.string().optional()), - CLIENT_GITLAB_LOGIN_URL: zpStr(z.string().optional().default(process.env.URL_GITLAB_LOGIN ?? GITLAB_URL)), // fallback since URL_GITLAB_LOGIN has been renamed + CLIENT_GITLAB_LOGIN_URL: zpStr( + z + .string() + .optional() + .default(process.env.URL_GITLAB_LOGIN ?? GITLAB_URL) + ), // fallback since URL_GITLAB_LOGIN has been renamed // integration client secrets // heroku CLIENT_ID_HEROKU: zpStr(z.string().optional()), @@ -121,7 +126,7 @@ export const initEnvConfig = (logger: Logger) => { logger.error(parsedEnv.error.issues); process.exit(-1); } - + envCfg = Object.freeze(parsedEnv.data); return envCfg; }; diff --git a/backend/src/lib/config/request.ts b/backend/src/lib/config/request.ts index 091713727..8636b7476 100644 --- a/backend/src/lib/config/request.ts +++ b/backend/src/lib/config/request.ts @@ -5,6 +5,7 @@ export const request = axios.create(); axiosRetry(request, { retries: 3, + // eslint-disable-next-line retryDelay: axiosRetry.exponentialDelay, retryCondition: (err) => axiosRetry.isNetworkError(err) || axiosRetry.isRetryableError(err) }); diff --git a/backend/src/lib/crypto/encryption.ts b/backend/src/lib/crypto/encryption.ts index ef1a7afe0..b3253b4aa 100644 --- a/backend/src/lib/crypto/encryption.ts +++ b/backend/src/lib/crypto/encryption.ts @@ -223,7 +223,7 @@ export const infisicalSymmetricEncypt = (data: string) => { throw new Error("Missing both encryption keys"); }; -export const infisicalSymmetricDecrypt = ({ +export const infisicalSymmetricDecrypt = ({ keyEncoding, ciphertext, tag, diff --git a/backend/src/lib/fn/array.ts b/backend/src/lib/fn/array.ts index abe8e3466..44b7d4f20 100644 --- a/backend/src/lib/fn/array.ts +++ b/backend/src/lib/fn/array.ts @@ -29,7 +29,7 @@ export const unique = ( ): T[] => { const valueMap = array.reduce( (acc, item) => { - const key = toKey ? toKey(item) : (item as any as string | number | symbol); + const key = toKey ? toKey(item) : (item as unknown as string | number | symbol); if (acc[key]) return acc; acc[key] = item; return acc; diff --git a/backend/src/lib/fn/object.ts b/backend/src/lib/fn/object.ts index 2fadc685c..563da728d 100644 --- a/backend/src/lib/fn/object.ts +++ b/backend/src/lib/fn/object.ts @@ -21,9 +21,9 @@ export const pick = ( * object. Optional second argument shakes out values * by custom evaluation. */ -export const shake = ( +export const shake = ( obj: T, - filter: (value: any) => boolean = (x) => x === undefined || x === null + filter: (value: unknown) => boolean = (x) => x === undefined || x === null ): Omit => { if (!obj) return {} as T; const keys = Object.keys(obj) as (keyof T)[]; diff --git a/backend/src/lib/knex/index.ts b/backend/src/lib/knex/index.ts index 515089e65..92479c978 100644 --- a/backend/src/lib/knex/index.ts +++ b/backend/src/lib/knex/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-misused-promises */ import { Knex } from "knex"; import { Tables } from "knex/types/tables"; @@ -15,22 +16,22 @@ export const withTransaction = (db: Knex, dal: K) => ({ ...dal }); -export type TFindFilter = Partial & { +export type TFindFilter = Partial & { $in?: Partial<{ [k in keyof R]: R[k][] }>; }; export const buildFindFilter = - ({ $in, ...filter }: TFindFilter) => + ({ $in, ...filter }: TFindFilter) => (bd: Knex.QueryBuilder) => { - bd.where(filter); + void bd.where(filter); if ($in) { Object.entries($in).forEach(([key, val]) => { - bd.whereIn(key as any, val as any); + void bd.whereIn(key as never, val as never); }); } return bd; }; -export type TFindOpt = { +export type TFindOpt = { limit?: number; offset?: number; sort?: Array<[keyof R, "asc" | "desc"] | [keyof R, "asc" | "desc", "first" | "last"]>; @@ -53,7 +54,7 @@ export const ormify = ( findById: async (id: string, tx?: Knex) => { try { const result = await (tx || db)(tableName) - .where({ id } as any) + .where({ id } as never) .first("*"); return result; } catch (error) { @@ -74,10 +75,10 @@ export const ormify = ( ) => { try { const query = (tx || db)(tableName).where(buildFindFilter(filter)); - if (limit) query.limit(limit); - if (offset) query.offset(offset); + if (limit) void query.limit(limit); + if (offset) void query.offset(offset); if (sort) { - query.orderBy( + void query.orderBy( sort.map(([column, order, nulls]) => ({ column: column as string, order, nulls })) ); } @@ -90,7 +91,7 @@ export const ormify = ( create: async (data: Tables[Tname]["insert"], tx?: Knex) => { try { const [res] = await (tx || db)(tableName) - .insert(data as any) + .insert(data as never) .returning("*"); return res; } catch (error) { @@ -101,7 +102,7 @@ export const ormify = ( try { if (!data.length) return []; const res = await (tx || db)(tableName) - .insert(data as any) + .insert(data as never) .returning("*"); return res; } catch (error) { @@ -111,8 +112,8 @@ export const ormify = ( updateById: async (id: string, data: Tables[Tname]["update"], tx?: Knex) => { try { const [res] = await (tx || db)(tableName) - .where({ id } as any) - .update(data as any) + .where({ id } as never) + .update(data as never) .returning("*"); return res; } catch (error) { @@ -127,7 +128,7 @@ export const ormify = ( try { const res = await (tx || db)(tableName) .where(buildFindFilter(filter)) - .update(data as any) + .update(data as never) .returning("*"); return res; } catch (error) { @@ -137,7 +138,7 @@ export const ormify = ( deleteById: async (id: string, tx?: Knex) => { try { const [res] = await (tx || db)(tableName) - .where({ id } as any) + .where({ id } as never) .delete() .returning("*"); return res; diff --git a/backend/src/lib/knex/join.ts b/backend/src/lib/knex/join.ts index 59144fbcc..6580bfa3d 100644 --- a/backend/src/lib/knex/join.ts +++ b/backend/src/lib/knex/join.ts @@ -1,7 +1,16 @@ +/* eslint-disable @typescript-eslint/ban-types */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +// TODO(akhilmhdh): make this better later + export const mergeOneToManyRelation = < - T extends Record, + T extends Record, Pk extends keyof T, - P extends Record, + P extends Record, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint C extends any, Ck extends string = "child" >( @@ -22,7 +31,7 @@ export const mergeOneToManyRelation = < const parent = parentMapper(row) as any; parent[childKey] = []; groupedRecord.push(parent); - prevPkId = pk; + prevPkId = pk as string; prevPkIndex += 1; } groupedRecord[prevPkIndex][childKey].push(childMapper(row)); @@ -41,6 +50,7 @@ export type TSqlPackRelationships< childrenMapper: C; }; +// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint export type TChildMapper = { key: keyof T; label: U; @@ -82,7 +92,7 @@ const sqlChildMapper = < const ck = `${prefix}-${label}-${doc[childPk]}`; const val = mapper(doc); if (!lookupTable.has(ck)) { - if (typeof val !== "undefined" && val !== null) docsByPk[pk as keyof P][label].push(val); + if (typeof val !== "undefined" && val !== null) docsByPk[pk][label].push(val); lookupTable.add(ck); } if (nestedMappers && val) { diff --git a/backend/src/lib/logger/index.ts b/backend/src/lib/logger/index.ts index df012e434..21cb66920 100644 --- a/backend/src/lib/logger/index.ts +++ b/backend/src/lib/logger/index.ts @@ -1 +1 @@ -export { initLogger,logger } from "./logger"; +export { initLogger, logger } from "./logger"; diff --git a/backend/src/lib/logger/logger.ts b/backend/src/lib/logger/logger.ts index 82db1725c..67e200c8a 100644 --- a/backend/src/lib/logger/logger.ts +++ b/backend/src/lib/logger/logger.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ // logger follows a singleton pattern // easier to use it that's all. import pino, { Logger } from "pino"; @@ -14,10 +15,10 @@ const logLevelToSeverityLookup: Record = { // eslint-disable-next-line import/no-mutable-exports export let logger: Readonly; -// akhilmhdh: -// The logger is not placed in the main app config to avoid a circular dependency. -// The config requires the logger to display errors when an invalid environment is supplied. -// On the other hand, the logger needs the config to obtain credentials for AWS or other transports. +// akhilmhdh: +// The logger is not placed in the main app config to avoid a circular dependency. +// The config requires the logger to display errors when an invalid environment is supplied. +// On the other hand, the logger needs the config to obtain credentials for AWS or other transports. // By keeping the logger separate, it becomes an independent package. const loggerConfig = z.object({ @@ -66,6 +67,7 @@ export const initLogger = async () => { }) } }, + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument transport ); return logger; diff --git a/backend/src/lib/zod/index.ts b/backend/src/lib/zod/index.ts index 331a5fbb6..629f42f68 100644 --- a/backend/src/lib/zod/index.ts +++ b/backend/src/lib/zod/index.ts @@ -1,4 +1,4 @@ -import { z,ZodTypeAny } from "zod"; +import { z, ZodTypeAny } from "zod"; // this is a patched zod string to remove empty string to undefined export const zpStr = ( diff --git a/backend/src/main.ts b/backend/src/main.ts index 4891157ad..c1a3d7207 100644 --- a/backend/src/main.ts +++ b/backend/src/main.ts @@ -18,19 +18,21 @@ const run = async () => { const server = await main({ db, smtp, logger, queue }); const bootstrap = await bootstrapCheck({ db }); + // eslint-disable-next-line process.on("SIGINT", async () => { await server.close(); await db.destroy(); process.exit(0); }); + // eslint-disable-next-line process.on("SIGTERM", async () => { await server.close(); await db.destroy(); process.exit(0); }); - server.listen({ + await server.listen({ port: appCfg.PORT, host: appCfg.HOST, listenTextResolver: (address) => { @@ -40,4 +42,4 @@ const run = async () => { }); }; -run(); +void run(); diff --git a/backend/src/queue/queue-service.ts b/backend/src/queue/queue-service.ts index 8a170487f..6065248d7 100644 --- a/backend/src/queue/queue-service.ts +++ b/backend/src/queue/queue-service.ts @@ -63,14 +63,14 @@ export type TQueueJobTypes = { export type TQueueServiceFactory = ReturnType; export const queueServiceFactory = (redisUrl: string) => { const connection = new Redis(redisUrl, { maxRetriesPerRequest: null }); - const queueContainer: Record< + const queueContainer = {} as Record< QueueName, Queue - > = {} as any; - const workerContainer: Record< + >; + const workerContainer = {} as Record< QueueName, Worker - > = {} as any; + >; const start = ( name: T, @@ -93,7 +93,7 @@ export const queueServiceFactory = (redisUrl: string) => { >(name, jobFn, { connection }); }; - const listen = async < + const listen = < T extends QueueName, U extends keyof WorkerListener >( diff --git a/backend/src/server/config/rateLimiter.ts b/backend/src/server/config/rateLimiter.ts index 7982cff63..444158cbf 100644 --- a/backend/src/server/config/rateLimiter.ts +++ b/backend/src/server/config/rateLimiter.ts @@ -6,7 +6,7 @@ import { getConfig } from "@app/lib/config/env"; export const globalRateLimiterCfg = (): RateLimitPluginOptions => { const appCfg = getConfig(); const redis = appCfg.isRedisConfigured - ? new Redis(appCfg.REDIS_URL as string, { connectTimeout: 500, maxRetriesPerRequest: 1 }) + ? new Redis(appCfg.REDIS_URL, { connectTimeout: 500, maxRetriesPerRequest: 1 }) : null; return { diff --git a/backend/src/server/plugins/auth/inject-identity.ts b/backend/src/server/plugins/auth/inject-identity.ts index f60b9f4c5..7411ee640 100644 --- a/backend/src/server/plugins/auth/inject-identity.ts +++ b/backend/src/server/plugins/auth/inject-identity.ts @@ -106,9 +106,7 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => { break; } case AuthMode.SERVICE_TOKEN: { - const serviceToken = await server.services.serviceToken.fnValidateServiceToken( - token as string - ); + const serviceToken = await server.services.serviceToken.fnValidateServiceToken(token); req.auth = { authMode: AuthMode.SERVICE_TOKEN as const, serviceToken, diff --git a/backend/src/server/plugins/auth/superAdmin.ts b/backend/src/server/plugins/auth/superAdmin.ts index 2cd7181bd..d5dee581b 100644 --- a/backend/src/server/plugins/auth/superAdmin.ts +++ b/backend/src/server/plugins/auth/superAdmin.ts @@ -1,12 +1,17 @@ -import { FastifyRequest } from "fastify"; +import { FastifyReply, FastifyRequest, HookHandlerDoneFunction } from "fastify"; import { UnauthorizedError } from "@app/lib/errors"; import { ActorType } from "@app/services/auth/auth-type"; -export const verifySuperAdmin = async (req: T) => { +export const verifySuperAdmin = ( + req: T, + _res: FastifyReply, + done: HookHandlerDoneFunction +) => { if (req.auth.actor !== ActorType.USER || !req.auth.user.superAdmin) throw new UnauthorizedError({ name: "Unauthorized access", message: "Requires superadmin access" }); + done(); }; diff --git a/backend/src/server/plugins/auth/verify-auth.ts b/backend/src/server/plugins/auth/verify-auth.ts index cfd856dbe..c854e28cc 100644 --- a/backend/src/server/plugins/auth/verify-auth.ts +++ b/backend/src/server/plugins/auth/verify-auth.ts @@ -1,11 +1,11 @@ -import { FastifyRequest } from "fastify"; +import { FastifyReply, FastifyRequest, HookHandlerDoneFunction } from "fastify"; import { UnauthorizedError } from "@app/lib/errors"; import { AuthMode } from "@app/services/auth/auth-type"; export const verifyAuth = (authStrats: AuthMode[]) => - async (req: T) => { + (req: T, _res: FastifyReply, done: HookHandlerDoneFunction) => { if (!Array.isArray(authStrats)) throw new Error("Auth strategy must be array"); if (!req.auth) throw new UnauthorizedError({ name: "Unauthorized access", message: "Token missing" }); @@ -14,4 +14,5 @@ export const verifyAuth = if (!isAccessAllowed) { throw new UnauthorizedError({ name: `${req.url} Unauthorized Access` }); } + done(); }; diff --git a/backend/src/server/plugins/error-handler.ts b/backend/src/server/plugins/error-handler.ts index cacc91885..977d71d90 100644 --- a/backend/src/server/plugins/error-handler.ts +++ b/backend/src/server/plugins/error-handler.ts @@ -5,7 +5,6 @@ import { ZodError } from "zod"; import { BadRequestError, DatabaseError, - ForbiddenRequestError, InternalServerError, UnauthorizedError } from "@app/lib/errors"; @@ -14,21 +13,25 @@ export const fastifyErrHandler = fastifyPlugin(async (server: FastifyZodProvider server.setErrorHandler((error, req, res) => { req.log.error(error); if (error instanceof BadRequestError) { - res.status(400).send({ statusCode: 400, message: error.message, error: error.name }); + void res.status(400).send({ statusCode: 400, message: error.message, error: error.name }); } else if (error instanceof UnauthorizedError) { - res.status(403).send({ statusCode: 403, message: error.message, error: error.name }); + void res.status(403).send({ statusCode: 403, message: error.message, error: error.name }); } else if (error instanceof DatabaseError || error instanceof InternalServerError) { - res.status(500).send({ statusCode: 500, message: "Something went wrong", error: error.name }); + void res + .status(500) + .send({ statusCode: 500, message: "Something went wrong", error: error.name }); } else if (error instanceof ZodError) { - res.status(403).send({ statusCode: 403, error: "ValidationFailure", message: error.issues }); + void res + .status(403) + .send({ statusCode: 403, error: "ValidationFailure", message: error.issues }); } else if (error instanceof ForbiddenError) { - res.status(401).send({ + void res.status(401).send({ statusCode: 401, error: "PermissionDenied", message: `You are not allowed to ${error.action} on ${error.subjectType}` }); } else { - res.send(error); + void res.send(error); } }); }); diff --git a/backend/src/server/plugins/external-nextjs.ts b/backend/src/server/plugins/external-nextjs.ts index 010e92f96..89cf45125 100644 --- a/backend/src/server/plugins/external-nextjs.ts +++ b/backend/src/server/plugins/external-nextjs.ts @@ -20,17 +20,19 @@ export const registerExternalNextjs = async ( if (standaloneMode) { const nextJsBuildPath = path.join(dir, "frontend-build"); - const { default: conf } = await import( + const { default: conf } = (await import( path.join(dir, "frontend-build/.next/required-server-files.json"), // @ts-expect-error type { assert: { type: "json" } } - ); + )) as { default: { config: string } }; + /* eslint-disable */ const { default: NextServer } = ( await import(path.join(dir, "frontend-build/node_modules/next/dist/server/next-server.js")) ).default; + const nextApp = new NextServer({ dev: false, dir: nextJsBuildPath, @@ -52,5 +54,6 @@ export const registerExternalNextjs = async ( }); server.addHook("onClose", () => nextApp.close()); await nextApp.prepare(); + /* eslint-enable */ } }; diff --git a/backend/src/server/plugins/secret-scanner.ts b/backend/src/server/plugins/secret-scanner.ts index f90b39114..8790d54d4 100644 --- a/backend/src/server/plugins/secret-scanner.ts +++ b/backend/src/server/plugins/secret-scanner.ts @@ -1,3 +1,4 @@ +import { PushEvent } from "@octokit/webhooks-types"; import { Probot } from "probot"; import SmeeClient from "smee-client"; @@ -22,7 +23,7 @@ export const registerSecretScannerGhApp = async (server: FastifyZodProvider) => app.on("push", async (context) => { const { payload } = context; - await server.services.secretScanning.handleRepoPushEvent(payload as any); + await server.services.secretScanning.handleRepoPushEvent(payload as PushEvent); }); }; @@ -49,16 +50,17 @@ export const registerSecretScannerGhApp = async (server: FastifyZodProvider) => method: "POST", url: "/", handler: async (req, res) => { - const eventName = req.headers["x-github-event"] as any; + const eventName = req.headers["x-github-event"]; const signatureSHA256 = req.headers["x-hub-signature-256"] as string; const id = req.headers["x-github-delivery"] as string; await probot.webhooks.verifyAndReceive({ id, + // @ts-expect-error type name: eventName, payload: req.body as string, signature: signatureSHA256 }); - res.send("ok"); + void res.send("ok"); } }); } diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index f6971b7ea..be754097a 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -118,7 +118,7 @@ export const registerRoutes = async ( queue: queueService }: { db: Knex; smtp: TSmtpService; queue: TQueueServiceFactory } ) => { - server.register(registerSecretScannerGhApp, { prefix: "/ss-webhook" }); + await server.register(registerSecretScannerGhApp, { prefix: "/ss-webhook" }); // db layers const userDAL = userDALFactory(db); diff --git a/backend/src/server/routes/v1/admin-router.ts b/backend/src/server/routes/v1/admin-router.ts index e5ea127c5..b8b61216b 100644 --- a/backend/src/server/routes/v1/admin-router.ts +++ b/backend/src/server/routes/v1/admin-router.ts @@ -39,10 +39,10 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => { }) } }, - onRequest: (req, _, done) => { - verifyAuth([AuthMode.JWT, AuthMode.API_KEY])(req); - verifySuperAdmin(req); - done(); + onRequest: (req, res, done) => { + verifyAuth([AuthMode.JWT, AuthMode.API_KEY])(req, res, () => { + verifySuperAdmin(req, res, done); + }); }, handler: async (req) => { const config = await server.services.superAdmin.updateServerCfg(req.body); @@ -97,7 +97,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => { } }); - res.setCookie("jid", token.refresh, { + void res.setCookie("jid", token.refresh, { httpOnly: true, path: "/", sameSite: "strict", diff --git a/backend/src/server/routes/v1/auth-router.ts b/backend/src/server/routes/v1/auth-router.ts index 871b56c1f..0d8621727 100644 --- a/backend/src/server/routes/v1/auth-router.ts +++ b/backend/src/server/routes/v1/auth-router.ts @@ -15,8 +15,8 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => { server.route({ url: "/logout", method: "POST", - config:{ - rateLimit:authRateLimit + config: { + rateLimit: authRateLimit }, schema: { response: { @@ -31,7 +31,7 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => { if (req.auth.authMode === AuthMode.JWT) { await server.services.login.logout(req.permission.id, req.auth.tokenVersionId); } - res.cookie("jid", "", { + void res.cookie("jid", "", { httpOnly: true, path: "/", sameSite: "strict", diff --git a/backend/src/server/routes/v1/integration-router.ts b/backend/src/server/routes/v1/integration-router.ts index db73bf293..a7df57a54 100644 --- a/backend/src/server/routes/v1/integration-router.ts +++ b/backend/src/server/routes/v1/integration-router.ts @@ -57,6 +57,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { projectId: integrationAuth.projectId, event: { type: EventType.CREATE_INTEGRATION, + // eslint-disable-next-line metadata: shake({ integrationId: integration.id.toString(), integration: integration.integration, @@ -71,6 +72,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { targetServiceId: integration.targetServiceId, path: integration.path, region: integration.region + // eslint-disable-next-line }) as any } }); @@ -138,6 +140,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { projectId: integration.projectId, event: { type: EventType.DELETE_INTEGRATION, + // eslint-disable-next-line metadata: shake({ integrationId: integration.id, integration: integration.integration, @@ -152,6 +155,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => { targetServiceId: integration.targetServiceId, path: integration.path, region: integration.region + // eslint-disable-next-line }) as any } }); diff --git a/backend/src/server/routes/v1/password-router.ts b/backend/src/server/routes/v1/password-router.ts index 8ec7697f7..b3a9044c6 100644 --- a/backend/src/server/routes/v1/password-router.ts +++ b/backend/src/server/routes/v1/password-router.ts @@ -12,7 +12,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { method: "POST", url: "/srp1", config: { - rateLimit:passwordRateLimit + rateLimit: passwordRateLimit }, schema: { body: z.object({ @@ -39,7 +39,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { method: "POST", url: "/change-password", config: { - rateLimit:passwordRateLimit + rateLimit: passwordRateLimit }, schema: { body: z.object({ @@ -64,7 +64,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { const appCfg = getConfig(); await server.services.password.changePassword({ ...req.body, userId: req.permission.id }); - res.cookie("jid", appCfg.COOKIE_SECRET_SIGN_KEY, { + void res.cookie("jid", appCfg.COOKIE_SECRET_SIGN_KEY, { httpOnly: true, path: "/", sameSite: "strict", @@ -78,7 +78,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { method: "POST", url: "/email/password-reset", config: { - rateLimit:passwordRateLimit + rateLimit: passwordRateLimit }, schema: { body: z.object({ @@ -103,7 +103,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { method: "POST", url: "/email/password-reset-verify", config: { - rateLimit:passwordRateLimit + rateLimit: passwordRateLimit }, schema: { body: z.object({ @@ -136,7 +136,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { method: "POST", url: "/backup-private-key", config: { - rateLimit:passwordRateLimit + rateLimit: passwordRateLimit }, onRequest: verifyAuth([AuthMode.JWT]), schema: { @@ -156,10 +156,10 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const token = validateSignUpAuthorization(req.headers.authorization as string, "",false)! + const token = validateSignUpAuthorization(req.headers.authorization as string, "", false)!; const backupPrivateKey = await server.services.password.createBackupPrivateKey({ ...req.body, - userId: token.userId, + userId: token.userId }); if (!backupPrivateKey) throw new Error("Failed to create backup key"); @@ -171,7 +171,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { method: "GET", url: "/backup-private-key", config: { - rateLimit:passwordRateLimit + rateLimit: passwordRateLimit }, schema: { response: { @@ -182,7 +182,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const token = validateSignUpAuthorization(req.headers.authorization as string, "",false)! + const token = validateSignUpAuthorization(req.headers.authorization as string, "", false)!; const backupPrivateKey = await server.services.password.getBackupPrivateKeyOfUser( token.userId ); @@ -213,10 +213,10 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => { } }, handler: async (req) => { - const token = validateSignUpAuthorization(req.headers.authorization as string, "",false)! + const token = validateSignUpAuthorization(req.headers.authorization as string, "", false)!; await server.services.password.resetPasswordByBackupKey({ ...req.body, - userId: token.userId, + userId: token.userId }); return { message: "Successfully updated backup private key" }; diff --git a/backend/src/server/routes/v1/project-router.ts b/backend/src/server/routes/v1/project-router.ts index 5e8ee8b46..b7574e35c 100644 --- a/backend/src/server/routes/v1/project-router.ts +++ b/backend/src/server/routes/v1/project-router.ts @@ -255,7 +255,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { response: { 200: z.object({ invitee: UsersSchema, - latestKey: ProjectKeysSchema + latestKey: ProjectKeysSchema.optional() }) } }, diff --git a/backend/src/server/routes/v1/sso-router.ts b/backend/src/server/routes/v1/sso-router.ts index f3d5288b0..ed882041b 100644 --- a/backend/src/server/routes/v1/sso-router.ts +++ b/backend/src/server/routes/v1/sso-router.ts @@ -1,3 +1,11 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +// All the any rules are disabled because passport typesense with fastify is really poor + import { Authenticator } from "@fastify/passport"; import fastifySession from "@fastify/session"; import { Strategy as GitHubStrategy } from "passport-github"; @@ -32,6 +40,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { callbackURL: `${appCfg.SITE_URL}/api/v1/sso/google`, scope: ["profile", " email"] }, + // eslint-disable-next-line async (req, _accessToken, _refreshToken, profile, cb) => { try { const email = profile?.emails?.[0]?.value; @@ -74,6 +83,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { callbackURL: `${appCfg.SITE_URL}/api/v1/sso/github`, scope: ["user:email"] }, + // eslint-disable-next-line async (req, accessToken, _refreshToken, profile, cb) => { try { const ghEmails = await fetchGithubEmails(accessToken); @@ -152,6 +162,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { state: req.query.callback_port, authInfo: false // this is due to zod type difference + // eslint-disable-next-line @typescript-eslint/no-explicit-any }) as any )(req, res), handler: () => {} @@ -165,7 +176,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { failureRedirect: "/login/provider/error", authInfo: false // this is due to zod type difference - }) as any, + }) as never, handler: (req, res) => { if (req.passportUser.isUserCompleted) { return res.redirect( @@ -242,6 +253,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { state: req.query.callback_port, authInfo: false // this is due to zod type difference + // eslint-disable-next-line @typescript-eslint/no-explicit-any }) as any )(req, res), handler: () => {} @@ -255,6 +267,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { failureRedirect: "/login/provider/error", authInfo: false // this is due to zod type difference + // eslint-disable-next-line @typescript-eslint/no-explicit-any }) as any, handler: (req, res) => { if (req.passportUser.isUserCompleted) { diff --git a/backend/src/server/routes/v1/webhook-router.ts b/backend/src/server/routes/v1/webhook-router.ts index 558192f68..2b3e66398 100644 --- a/backend/src/server/routes/v1/webhook-router.ts +++ b/backend/src/server/routes/v1/webhook-router.ts @@ -183,7 +183,11 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => { querystring: z.object({ workspaceId: z.string().trim(), environment: z.string().trim().optional(), - secretPath: z.string().trim().optional().transform((val)=> val?removeTrailingSlash(val):val) + secretPath: z + .string() + .trim() + .optional() + .transform((val) => (val ? removeTrailingSlash(val) : val)) }), response: { 200: z.object({ diff --git a/backend/src/server/routes/v2/index.ts b/backend/src/server/routes/v2/index.ts index a73f9de52..1f423c084 100644 --- a/backend/src/server/routes/v2/index.ts +++ b/backend/src/server/routes/v2/index.ts @@ -19,8 +19,8 @@ export const registerV2Routes = async (server: FastifyZodProvider) => { ); await server.register( async (projectServer) => { - projectServer.register(registerProjectRouter); - projectServer.register(registerIdentityProjectRouter); + await projectServer.register(registerProjectRouter); + await projectServer.register(registerIdentityProjectRouter); }, { prefix: "/workspace" } ); diff --git a/backend/src/server/routes/v2/mfa-router.ts b/backend/src/server/routes/v2/mfa-router.ts index 02006a470..6ba5a9f49 100644 --- a/backend/src/server/routes/v2/mfa-router.ts +++ b/backend/src/server/routes/v2/mfa-router.ts @@ -1,8 +1,8 @@ -import jwt, { JwtPayload } from "jsonwebtoken"; +import jwt from "jsonwebtoken"; import { z } from "zod"; import { getConfig } from "@app/lib/config/env"; -import { AuthTokenType } from "@app/services/auth/auth-type"; +import { AuthModeMfaJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type"; export const registerMfaRouter = async (server: FastifyZodProvider) => { const cfg = getConfig(); @@ -12,16 +12,16 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => { const authorizationHeader = req.headers.authorization; if (!authorizationHeader || !authorizationHeader.startsWith("Bearer ")) { - res.status(401).send({ error: "Missing bearer token" }); + void res.status(401).send({ error: "Missing bearer token" }); return res; } const token = authorizationHeader.split(" ")[1]; if (!token) { - res.status(401).send({ error: "Missing bearer token" }); + void res.status(401).send({ error: "Missing bearer token" }); return res; } - const decodedToken = jwt.verify(token, cfg.AUTH_SECRET) as JwtPayload; + const decodedToken = jwt.verify(token, cfg.AUTH_SECRET) as AuthModeMfaJwtTokenPayload; if (decodedToken.authTokenType !== AuthTokenType.MFA_TOKEN) throw new Error("Unauthorized access"); @@ -79,7 +79,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => { mfaToken: req.body.mfaToken }); - res.setCookie("jid", token.refresh, { + void res.setCookie("jid", token.refresh, { httpOnly: true, path: "/", sameSite: "strict", diff --git a/backend/src/server/routes/v2/project-router.ts b/backend/src/server/routes/v2/project-router.ts index 86f25d89d..e90a36060 100644 --- a/backend/src/server/routes/v2/project-router.ts +++ b/backend/src/server/routes/v2/project-router.ts @@ -37,7 +37,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { event: { type: EventType.GET_WORKSPACE_KEY, metadata: { - keyId: key.id + keyId: key?.id as string } } }); diff --git a/backend/src/server/routes/v2/user-router.ts b/backend/src/server/routes/v2/user-router.ts index 071a70539..cf34a9522 100644 --- a/backend/src/server/routes/v2/user-router.ts +++ b/backend/src/server/routes/v2/user-router.ts @@ -26,7 +26,10 @@ export const registerUserRouter = async (server: FastifyZodProvider) => { }, preHandler: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]), handler: async (req) => { - const user = await server.services.user.toggleUserMfa(req.permission.id, req.body.isMfaEnabled); + const user = await server.services.user.toggleUserMfa( + req.permission.id, + req.body.isMfaEnabled + ); return { user }; } }); diff --git a/backend/src/server/routes/v3/login-router.ts b/backend/src/server/routes/v3/login-router.ts index 1c513c183..0cda8e5ff 100644 --- a/backend/src/server/routes/v3/login-router.ts +++ b/backend/src/server/routes/v3/login-router.ts @@ -81,7 +81,7 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => { return { mfaEnabled: true, token: data.token } as const; // for discriminated union } - res.setCookie("jid", data.token.refresh, { + void res.setCookie("jid", data.token.refresh, { httpOnly: true, path: "/", sameSite: "strict", diff --git a/backend/src/server/routes/v3/signup-router.ts b/backend/src/server/routes/v3/signup-router.ts index fe64a4ec2..62f197b54 100644 --- a/backend/src/server/routes/v3/signup-router.ts +++ b/backend/src/server/routes/v3/signup-router.ts @@ -101,13 +101,13 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => { authorization: req.headers.authorization as string }); - server.services.telemetry.sendLoopsEvent( + void server.services.telemetry.sendLoopsEvent( user.email, user.firstName || "", user.lastName || "" ); - server.services.telemetry.sendPostHogEvents({ + void server.services.telemetry.sendPostHogEvents({ event: PostHogEventTypes.UserSignedUp, distinctId: user.email, properties: { @@ -116,7 +116,7 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => { } }); - res.setCookie("jid", refreshToken, { + await res.setCookie("jid", refreshToken, { httpOnly: true, path: "/", sameSite: "strict", @@ -168,7 +168,7 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => { userAgent }); - res.setCookie("jid", refreshToken, { + await res.setCookie("jid", refreshToken, { httpOnly: true, path: "/", sameSite: "strict", diff --git a/backend/src/services/auth-token/auth-token-dal.ts b/backend/src/services/auth-token/auth-token-dal.ts index edd8ef74c..87f2a653e 100644 --- a/backend/src/services/auth-token/auth-token-dal.ts +++ b/backend/src/services/auth-token/auth-token-dal.ts @@ -7,8 +7,6 @@ import { ormify } from "@app/lib/knex"; import { TDeleteTokenForUserDALDTO } from "./auth-token-types"; -export type TTokenDALConfig = {}; - export type TTokenDALFactory = ReturnType; export const tokenDALFactory = (db: TDbClient) => { diff --git a/backend/src/services/auth/auth-type.ts b/backend/src/services/auth/auth-type.ts index 183c6170e..26417b0e8 100644 --- a/backend/src/services/auth/auth-type.ts +++ b/backend/src/services/auth/auth-type.ts @@ -41,6 +41,11 @@ export type AuthModeJwtTokenPayload = { accessVersion: number; }; +export type AuthModeMfaJwtTokenPayload = { + authTokenType: AuthTokenType.MFA_TOKEN; + userId: string; +}; + export type AuthModeRefreshJwtTokenPayload = { authTokenType: AuthTokenType.REFRESH_TOKEN; userId: string; diff --git a/backend/src/services/identity-access-token/identity-access-token-dal.ts b/backend/src/services/identity-access-token/identity-access-token-dal.ts index 5919136a0..edd4ef91e 100644 --- a/backend/src/services/identity-access-token/identity-access-token-dal.ts +++ b/backend/src/services/identity-access-token/identity-access-token-dal.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName,TIdentityAccessTokens } from "@app/db/schemas"; +import { TableName, TIdentityAccessTokens } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify, selectAllTableCols } from "@app/lib/knex"; diff --git a/backend/src/services/identity-access-token/identity-access-token-service.ts b/backend/src/services/identity-access-token/identity-access-token-service.ts index 7509b9dff..f5e3379af 100644 --- a/backend/src/services/identity-access-token/identity-access-token-service.ts +++ b/backend/src/services/identity-access-token/identity-access-token-service.ts @@ -33,7 +33,11 @@ export const identityAccessTokenServiceFactory = ({ createdAt: accessTokenCreatedAt } = identityAccessToken; - if (accessTokenNumUsesLimit > 0 && accessTokenNumUses > 0 && accessTokenNumUses >= accessTokenNumUsesLimit) { + if ( + accessTokenNumUsesLimit > 0 && + accessTokenNumUses > 0 && + accessTokenNumUses >= accessTokenNumUsesLimit + ) { throw new BadRequestError({ message: "Unable to renew because access token number of uses limit reached" }); @@ -88,7 +92,9 @@ export const identityAccessTokenServiceFactory = ({ const renewAccessToken = async ({ accessToken }: TRenewAccessTokenDTO) => { const appCfg = getConfig(); - const decodedToken = jwt.verify(accessToken, appCfg.AUTH_SECRET) as JwtPayload; + const decodedToken = jwt.verify(accessToken, appCfg.AUTH_SECRET) as JwtPayload & { + identityAccessTokenId: string; + }; if (decodedToken.authTokenType !== AuthTokenType.IDENTITY_ACCESS_TOKEN) throw new UnauthorizedError(); diff --git a/backend/src/services/identity/identity-service.ts b/backend/src/services/identity/identity-service.ts index 09fb5fb36..bc87b1f06 100644 --- a/backend/src/services/identity/identity-service.ts +++ b/backend/src/services/identity/identity-service.ts @@ -56,7 +56,6 @@ export const identityServiceFactory = ({ return newIdentity; }); - return identity; }; diff --git a/backend/src/services/integration-auth/integration-app-list.ts b/backend/src/services/integration-auth/integration-app-list.ts index 39e629606..cd72fc60b 100644 --- a/backend/src/services/integration-auth/integration-app-list.ts +++ b/backend/src/services/integration-auth/integration-app-list.ts @@ -59,8 +59,8 @@ const getAppsGCPSecretManager = async ({ accessToken }: { accessToken: string }) ...(pageToken ? { pageToken } : {}) }); - const res: GCPGetProjectsRes = ( - await request.get(`${IntegrationUrls.GCP_API_URL}/v1/projects`, { + const res = ( + await request.get(`${IntegrationUrls.GCP_API_URL}/v1/projects`, { params, headers: { Authorization: `Bearer ${accessToken}`, @@ -81,8 +81,8 @@ const getAppsGCPSecretManager = async ({ accessToken }: { accessToken: string }) // eslint-disable-next-line for await (const gcpApp of gcpApps) { try { - const res: GCPGetServiceRes = ( - await request.get( + const res = ( + await request.get( `${IntegrationUrls.GCP_SERVICE_USAGE_URL}/v1/projects/${gcpApp.projectId}/services/${IntegrationUrls.GCP_SECRET_MANAGER_SERVICE_NAME}`, { headers: { @@ -113,7 +113,7 @@ const getAppsGCPSecretManager = async ({ accessToken }: { accessToken: string }) */ const getAppsHeroku = async ({ accessToken }: { accessToken: string }) => { const res = ( - await request.get(`${IntegrationUrls.HEROKU_API_URL}/apps`, { + await request.get<{ name: string }[]>(`${IntegrationUrls.HEROKU_API_URL}/apps`, { headers: { Accept: "application/vnd.heroku+json; version=3", Authorization: `Bearer ${accessToken}` @@ -121,7 +121,7 @@ const getAppsHeroku = async ({ accessToken }: { accessToken: string }) => { }) ).data; - const apps = res.map((a: any) => ({ + const apps = res.map((a) => ({ name: a.name })); @@ -139,22 +139,25 @@ const getAppsVercel = async ({ accessToken: string; }) => { const res = ( - await request.get(`${IntegrationUrls.VERCEL_API_URL}/v9/projects`, { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" - }, - ...(teamId - ? { - params: { - teamId + await request.get<{ projects: { name: string; id: string }[] }>( + `${IntegrationUrls.VERCEL_API_URL}/v9/projects`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + }, + ...(teamId + ? { + params: { + teamId + } } - } - : {}) - }) + : {}) + } + ) ).data; - const apps = res.projects.map((a: any) => ({ + const apps = res.projects.map((a) => ({ name: a.name, appId: a.id })); @@ -166,7 +169,7 @@ const getAppsVercel = async ({ * Return list of sites for Netlify integration */ const getAppsNetlify = async ({ accessToken }: { accessToken: string }) => { - const apps: any = []; + const apps: Array<{ name: string; appId: string }> = []; let page = 1; const perPage = 10; let hasMorePages = true; @@ -179,15 +182,18 @@ const getAppsNetlify = async ({ accessToken }: { accessToken: string }) => { filter: "all" }); - const { data } = await request.get(`${IntegrationUrls.NETLIFY_API_URL}/api/v1/sites`, { - params, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + const { data } = await request.get<{ name: string; site_id: string }[]>( + `${IntegrationUrls.NETLIFY_API_URL}/api/v1/sites`, + { + params, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }); + ); - data.forEach((a: any) => { + data.forEach((a) => { apps.push({ name: a.name, appId: a.site_id @@ -238,8 +244,8 @@ const getAppsGithub = async ({ accessToken }: { accessToken: string }) => { } ); - if (response.data.length > 0) { - repos = repos.concat(response.data); + if ((response.data as GitHubApp[]).length > 0) { + repos = repos.concat(response.data as GitHubApp[]); page += 1; } else { hasMore = false; @@ -267,16 +273,19 @@ const getAppsGithub = async ({ accessToken }: { accessToken: string }) => { */ const getAppsRender = async ({ accessToken }: { accessToken: string }) => { const res = ( - await request.get(`${IntegrationUrls.RENDER_API_URL}/v1/services`, { - headers: { - Authorization: `Bearer ${accessToken}`, - Accept: "application/json", - "Accept-Encoding": "application/json" + await request.get<{ service: { name: string; id: string } }[]>( + `${IntegrationUrls.RENDER_API_URL}/v1/services`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: "application/json", + "Accept-Encoding": "application/json" + } } - }) + ) ).data; - const apps = res.map((a: any) => ({ + const apps = res.map((a) => ({ name: a.service.name, appId: a.service.id })); @@ -309,7 +318,9 @@ const getAppsRailway = async ({ accessToken }: { accessToken: string }) => { projects: { edges } } } - } = await request.post( + } = await request.post<{ + data: { projects: { edges: { node: { name: string; id: string } }[] } }; + }>( IntegrationUrls.RAILWAY_API_URL, { query, @@ -324,7 +335,7 @@ const getAppsRailway = async ({ accessToken }: { accessToken: string }) => { } ); - const apps = edges.map((e: any) => ({ + const apps = edges.map((e) => ({ name: e.node.name, appId: e.node.id })); @@ -343,16 +354,19 @@ const getAppsLaravelForge = async ({ serverId?: string; }) => { const res = ( - await request.get(`${IntegrationUrls.LARAVELFORGE_API_URL}/api/v1/servers/${serverId}/sites`, { - headers: { - Authorization: `Bearer ${accessToken}`, - Accept: "application/json", - "Content-Type": "application/json" + await request.get<{ sites: { name: string; id: string }[] }>( + `${IntegrationUrls.LARAVELFORGE_API_URL}/api/v1/servers/${serverId}/sites`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: "application/json", + "Content-Type": "application/json" + } } - }) + ) ).data.sites; - const apps = res.map((a: any) => ({ + const apps = res.map((a) => ({ name: a.name, appId: a.id })); @@ -382,8 +396,8 @@ const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => { } `; - const res: FlyioApp[] = ( - await request.post( + const res = ( + await request.post<{ data: { apps: { nodes: FlyioApp[] } } }>( IntegrationUrls.FLYIO_API_URL, { query, @@ -401,7 +415,7 @@ const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => { ) ).data.data.apps.nodes; - const apps = res.map((a: FlyioApp) => ({ + const apps = res.map((a) => ({ name: a.name, appId: a.id })); @@ -414,7 +428,7 @@ const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => { */ const getAppsCircleCI = async ({ accessToken }: { accessToken: string }) => { const res = ( - await request.get(`${IntegrationUrls.CIRCLECI_API_URL}/v1.1/projects`, { + await request.get<{ reponame: string }[]>(`${IntegrationUrls.CIRCLECI_API_URL}/v1.1/projects`, { headers: { "Circle-Token": accessToken, "Accept-Encoding": "application/json" @@ -422,7 +436,7 @@ const getAppsCircleCI = async ({ accessToken }: { accessToken: string }) => { }) ).data; - const apps = res?.map((a: any) => ({ + const apps = res?.map((a) => ({ name: a?.reponame })); @@ -431,7 +445,7 @@ const getAppsCircleCI = async ({ accessToken }: { accessToken: string }) => { const getAppsTravisCI = async ({ accessToken }: { accessToken: string }) => { const res = ( - await request.get(`${IntegrationUrls.TRAVISCI_API_URL}/repos`, { + await request.get<{ id: string; slug: string }[]>(`${IntegrationUrls.TRAVISCI_API_URL}/repos`, { headers: { Authorization: `token ${accessToken}`, "Accept-Encoding": "application/json" @@ -439,7 +453,7 @@ const getAppsTravisCI = async ({ accessToken }: { accessToken: string }) => { }) ).data; - const apps = res?.map((a: any) => ({ + const apps = res?.map((a) => ({ name: a?.slug?.split("/")[1], appId: a?.id })); @@ -458,7 +472,7 @@ const getAppsTerraformCloud = async ({ workspacesId?: string; }) => { const res = ( - await request.get( + await request.get<{ data: { attributes: { name: string }; id: string } }>( `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/workspaces/${workspacesId}`, { headers: { @@ -510,15 +524,18 @@ const getAppsGitlab = async ({ per_page: String(perPage) }); - const { data } = await request.get(`${gitLabApiUrl}/v4/groups/${teamId}/projects`, { - params, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + const { data } = await request.get<{ name: string; id: string }[]>( + `${gitLabApiUrl}/v4/groups/${teamId}/projects`, + { + params, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }); + ); - data.forEach((a: any) => { + data.forEach((a) => { apps.push({ name: a.name, appId: a.id @@ -535,7 +552,7 @@ const getAppsGitlab = async ({ // case: fetch projects for individual in GitLab const { id } = ( - await request.get(`${gitLabApiUrl}/v4/user`, { + await request.get<{ id: string }>(`${gitLabApiUrl}/v4/user`, { headers: { Authorization: `Bearer ${accessToken}`, "Accept-Encoding": "application/json" @@ -549,15 +566,18 @@ const getAppsGitlab = async ({ per_page: String(perPage) }); - const { data } = await request.get(`${gitLabApiUrl}/v4/users/${id}/projects`, { - params, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + const { data } = await request.get<{ name: string; id: string }[]>( + `${gitLabApiUrl}/v4/users/${id}/projects`, + { + params, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }); + ); - data.forEach((a: any) => { + data.forEach((a) => { apps.push({ name: a.name, appId: a.id @@ -580,7 +600,7 @@ const getAppsGitlab = async ({ */ const getAppsTeamCity = async ({ accessToken, url }: { url: string; accessToken: string }) => { const res = ( - await request.get(`${url}/app/rest/projects`, { + await request.get<{ project: { name: string; id: string }[] }>(`${url}/app/rest/projects`, { headers: { Authorization: `Bearer ${accessToken}`, Accept: "application/json" @@ -588,7 +608,7 @@ const getAppsTeamCity = async ({ accessToken, url }: { url: string; accessToken: }) ).data.project.slice(1); - const apps = res.map((a: any) => ({ + const apps = res.map((a) => ({ name: a.name, appId: a.id })); @@ -600,14 +620,17 @@ const getAppsTeamCity = async ({ accessToken, url }: { url: string; accessToken: * Return list of projects for Supabase integration */ const getAppsSupabase = async ({ accessToken }: { accessToken: string }) => { - const { data } = await request.get(`${IntegrationUrls.SUPABASE_API_URL}/v1/projects`, { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + const { data } = await request.get<{ name: string; id: string }[]>( + `${IntegrationUrls.SUPABASE_API_URL}/v1/projects`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }); + ); - const apps = data.map((a: any) => ({ + const apps = data.map((a) => ({ name: a.name, appId: a.id })); @@ -619,14 +642,17 @@ const getAppsSupabase = async ({ accessToken }: { accessToken: string }) => { * Return list of accounts for the Checkly integration */ const getAppsCheckly = async ({ accessToken }: { accessToken: string }) => { - const { data } = await request.get(`${IntegrationUrls.CHECKLY_API_URL}/v1/accounts`, { - headers: { - Authorization: `Bearer ${accessToken}`, - Accept: "application/json" + const { data } = await request.get<{ name: string; id: string }[]>( + `${IntegrationUrls.CHECKLY_API_URL}/v1/accounts`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: "application/json" + } } - }); + ); - const apps = data.map((a: any) => ({ + const apps = data.map((a) => ({ name: a.name, appId: a.id })); @@ -644,7 +670,7 @@ const getAppsCloudflarePages = async ({ accessToken: string; accountId?: string; }) => { - const { data } = await request.get( + const { data } = await request.get<{ result: { name: string; id: string }[] }>( `${IntegrationUrls.CLOUDFLARE_PAGES_API_URL}/client/v4/accounts/${accountId}/pages/projects`, { headers: { @@ -654,7 +680,7 @@ const getAppsCloudflarePages = async ({ } ); - const apps = data.result.map((a: any) => ({ + const apps = data.result.map((a) => ({ name: a.name, appId: a.id })); @@ -671,7 +697,7 @@ const getAppsCloudflareWorkers = async ({ accessToken: string; accountId?: string; }) => { - const { data } = await request.get( + const { data } = await request.get<{ result: { id: string }[] }>( `${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accountId}/workers/services`, { headers: { @@ -681,7 +707,7 @@ const getAppsCloudflareWorkers = async ({ } ); - const apps = data.result.map((a: any) => ({ + const apps = data.result.map((a) => ({ name: a.id, appId: a.id })); @@ -759,14 +785,17 @@ const getAppsNorthflank = async ({ accessToken }: { accessToken: string }) => { data: { data: { projects } } - } = await request.get(`${IntegrationUrls.NORTHFLANK_API_URL}/v1/projects`, { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + } = await request.get<{ data: { projects: { name: string; id: string }[] } }>( + `${IntegrationUrls.NORTHFLANK_API_URL}/v1/projects`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }); + ); - const apps = projects.map((a: any) => ({ + const apps = projects.map((a) => ({ name: a.name, appId: a.id })); @@ -779,15 +808,18 @@ const getAppsNorthflank = async ({ accessToken }: { accessToken: string }) => { */ const getAppsCodefresh = async ({ accessToken }: { accessToken: string }) => { const res = ( - await request.get(`${IntegrationUrls.CODEFRESH_API_URL}/projects`, { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + await request.get<{ projects: { projectName: string; id: string }[] }>( + `${IntegrationUrls.CODEFRESH_API_URL}/projects`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }) + ) ).data; - const apps = res.projects.map((a: any) => ({ + const apps = res.projects.map((a) => ({ name: a.projectName, appId: a.id })); @@ -799,20 +831,23 @@ const getAppsCodefresh = async ({ accessToken }: { accessToken: string }) => { * Return list of projects for Windmill integration */ const getAppsWindmill = async ({ accessToken }: { accessToken: string }) => { - const { data } = await request.get(`${IntegrationUrls.WINDMILL_API_URL}/workspaces/list`, { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + const { data } = await request.get<{ id: string; name: string }[]>( + `${IntegrationUrls.WINDMILL_API_URL}/workspaces/list`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }); + ); // check for write access of secrets in windmill workspaces - const writeAccessCheck = data.map(async (app: any) => { + const writeAccessCheck = data.map(async (app) => { try { const userPath = "u/user/variable"; const folderPath = "f/folder/variable"; - const { data: writeUser } = await request.post( + const { data: writeUser } = await request.post( `${IntegrationUrls.WINDMILL_API_URL}/w/${app.id}/variables/create`, { path: userPath, @@ -828,7 +863,7 @@ const getAppsWindmill = async ({ accessToken }: { accessToken: string }) => { } ); - const { data: writeFolder } = await request.post( + const { data: writeFolder } = await request.post( `${IntegrationUrls.WINDMILL_API_URL}/w/${app.id}/variables/create`, { path: folderPath, @@ -869,15 +904,17 @@ const getAppsWindmill = async ({ accessToken }: { accessToken: string }) => { return app; } return { error: "cannot write secret" }; - } catch (err: any) { - return { error: err.message }; + } catch (err) { + return { error: (err as Error).message }; } }); const appsWriteResponses = await Promise.all(writeAccessCheck); - const appsWithWriteAccess = appsWriteResponses.filter((appRes: any) => !appRes.error); + const appsWithWriteAccess = appsWriteResponses.filter( + (appRes) => !(appRes as { error: string })?.error + ); - const apps = appsWithWriteAccess.map((a: any) => ({ + const apps = (appsWithWriteAccess as { id: string; name: string }[]).map((a) => ({ name: a.name, appId: a.id })); @@ -908,22 +945,27 @@ const getAppsDigitalOceanAppPlatform = async ({ accessToken }: { accessToken: st } const res = ( - await request.get(`${IntegrationUrls.DIGITAL_OCEAN_API_URL}/v2/apps`, { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + await request.get<{ apps: DigitalOceanApp[] }>( + `${IntegrationUrls.DIGITAL_OCEAN_API_URL}/v2/apps`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }) + ) ).data; - return (res.apps ?? []).map((a: DigitalOceanApp) => ({ + return (res.apps ?? []).map((a) => ({ name: a.spec.name, appId: a.id })); }; const getAppsHasuraCloud = async ({ accessToken }: { accessToken: string }) => { - const res = await request.post( + const res = await request.post<{ + data: { projects: { name: string; tenant: { id: string } }[] }; + }>( IntegrationUrls.HASURA_CLOUD_API_URL, { query: "query MyQuery { projects { name tenant { id } } }" @@ -936,19 +978,15 @@ const getAppsHasuraCloud = async ({ accessToken }: { accessToken: string }) => { } ); - const data = (res?.data?.data?.projects ?? []).map( - ({ name, tenant: { id: appId } }: { name: string; tenant: { id: string } }) => ({ name, appId }) - ); + const data = (res?.data?.data?.projects ?? []).map(({ name, tenant: { id: appId } }) => ({ + name, + appId + })); return data; }; /** * Return list of applications for Cloud66 integration - * @param {Object} obj - * @param {String} obj.accessToken - personal access token for Cloud66 API - * @returns {Object[]} apps - Cloud66 apps - * @returns {String} apps.name - name of Cloud66 app - * @returns {String} apps.appId - uid of Cloud66 app */ const getAppsCloud66 = async ({ accessToken }: { accessToken: string }) => { interface Cloud66Apps { @@ -979,19 +1017,19 @@ const getAppsCloud66 = async ({ accessToken }: { accessToken: string }) => { account_name: string; is_cluster: boolean; is_inside_cluster: boolean; - cluster_name: any; + cluster_name: string; application_address: string; configstore_namespace: string; } const stacks = ( - await request.get(`${IntegrationUrls.CLOUD_66_API_URL}/3/stacks`, { + await request.get<{ response: Cloud66Apps[] }>(`${IntegrationUrls.CLOUD_66_API_URL}/3/stacks`, { headers: { Authorization: `Bearer ${accessToken}`, "Accept-Encoding": "application/json" } }) - ).data.response as Cloud66Apps[]; + ).data.response; const apps = stacks.map((app) => ({ name: app.name, @@ -1016,7 +1054,7 @@ export const getApps = async ({ workspaceSlug?: string; url?: string | null; }): Promise => { - switch (integration) { + switch (integration as Integrations) { case Integrations.GCP_SECRET_MANAGER: return getAppsGCPSecretManager({ accessToken diff --git a/backend/src/services/integration-auth/integration-auth-service.ts b/backend/src/services/integration-auth/integration-auth-service.ts index 81b180ea4..519ae0230 100644 --- a/backend/src/services/integration-auth/integration-auth-service.ts +++ b/backend/src/services/integration-auth/integration-auth-service.ts @@ -906,7 +906,7 @@ export const integrationAuthServiceFactory = ({ } ); - secrets.forEach((a: any) => { + secrets.forEach((a) => { secretGroups.push({ name: a.name, groupId: a.id diff --git a/backend/src/services/integration-auth/integration-list.ts b/backend/src/services/integration-auth/integration-list.ts index 334a60e1d..d3cabbcb5 100644 --- a/backend/src/services/integration-auth/integration-list.ts +++ b/backend/src/services/integration-auth/integration-list.ts @@ -67,6 +67,7 @@ export enum IntegrationUrls { QOVERY_API_URL = "https://api.qovery.com", TERRAFORM_CLOUD_API_URL = "https://app.terraform.io", CLOUDFLARE_PAGES_API_URL = "https://api.cloudflare.com", + // eslint-disable-next-line CLOUDFLARE_WORKERS_API_URL = "https://api.cloudflare.com", BITBUCKET_API_URL = "https://api.bitbucket.org", CODEFRESH_API_URL = "https://g.codefresh.io/api", diff --git a/backend/src/services/integration-auth/integration-sync-secret.ts b/backend/src/services/integration-auth/integration-sync-secret.ts index 11ff5c5c2..6fe196c52 100644 --- a/backend/src/services/integration-auth/integration-sync-secret.ts +++ b/backend/src/services/integration-auth/integration-sync-secret.ts @@ -1,4 +1,11 @@ +/* eslint-disable @typescript-eslint/no-unsafe-return */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable no-param-reassign,no-await-in-loop */ +// Taken from old code and too much work at present thus disabling the above any rules +// resolve it later: akhilmhdh - TODO + import { CreateSecretCommand, GetSecretValueCommand, @@ -8,6 +15,7 @@ import { } from "@aws-sdk/client-secrets-manager"; import { Octokit } from "@octokit/rest"; import AWS from "aws-sdk"; +import { AxiosError } from "axios"; import sodium from "libsodium-wrappers"; import isEqual from "lodash.isequal"; import { z } from "zod"; @@ -87,8 +95,8 @@ const syncSecretsGCPSecretManager = async ({ ...(pageToken ? { pageToken } : {}) }); - const res: GCPSMListSecretsRes = ( - await request.get( + const res = ( + await request.get( `${IntegrationUrls.GCP_SECRET_MANAGER_URL}/v1/projects/${integration.appId}/secrets${filterParam}`, { params, @@ -309,7 +317,7 @@ const syncSecretsAzureKeyVault = async ({ }) ) ).reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.key]: secret }), @@ -378,8 +386,9 @@ const syncSecretsAzureKeyVault = async ({ isSecretSet = true; } catch (err) { - const error: any = err; - if (error?.response?.data?.error?.innererror?.code === "ObjectIsDeletedButRecoverable") { + const error = err as AxiosError; + // eslint-disable-next-line + if ((error?.response?.data as any)?.error?.innererror?.code === "ObjectIsDeletedButRecoverable") { await request.post( `${azIntegration.app}/deletedsecrets/${key}/recover?api-version=7.3`, {}, @@ -405,7 +414,7 @@ const syncSecretsAzureKeyVault = async ({ // Sync/push set secrets for await (const setSecret of setSecrets) { const { key, value } = setSecret; - setSecretAzureKeyVault({ + await setSecretAzureKeyVault({ key, value, integration, @@ -425,11 +434,6 @@ const syncSecretsAzureKeyVault = async ({ /** * Sync/push [secrets] to AWS parameter store - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessId - access id for AWS parameter store integration - * @param {String} obj.accessToken - access token for AWS parameter store integration */ const syncSecretsAWSParameterStore = async ({ integration, @@ -463,60 +467,60 @@ const syncSecretsAWSParameterStore = async ({ const parameterList = (await ssm.getParametersByPath(params).promise()).Parameters; - let awsParameterStoreSecretsObj: { - [key: string]: any; - } = {}; - - if (parameterList) { - awsParameterStoreSecretsObj = parameterList.reduce( - (obj: any, secret: any) => ({ + const awsParameterStoreSecretsObj = (parameterList || []) + .filter(({ Name }) => Boolean(Name)) + .reduce( + (obj, secret) => ({ ...obj, - [secret.Name.substring((integration.path as string).length)]: secret + [(secret.Name as string).substring((integration.path as string).length)]: secret }), - {} + {} as Record ); - } // Identify secrets to create - Object.keys(secrets).map(async (key) => { - if (!(key in awsParameterStoreSecretsObj)) { - // case: secret does not exist in AWS parameter store - // -> create secret - await ssm - .putParameter({ - Name: `${integration.path}${key}`, - Type: "SecureString", - Value: secrets[key].value, - Overwrite: true - }) - .promise(); - // case: secret exists in AWS parameter store - } else if (awsParameterStoreSecretsObj[key].Value !== secrets[key].value) { - // case: secret value doesn't match one in AWS parameter store - // -> update secret - await ssm - .putParameter({ - Name: `${integration.path}${key}`, - Type: "SecureString", - Value: secrets[key].value, - Overwrite: true - }) - .promise(); - } - }); + await Promise.all( + Object.keys(secrets).map(async (key) => { + if (!(key in awsParameterStoreSecretsObj)) { + // case: secret does not exist in AWS parameter store + // -> create secret + await ssm + .putParameter({ + Name: `${integration.path}${key}`, + Type: "SecureString", + Value: secrets[key].value, + Overwrite: true + }) + .promise(); + // case: secret exists in AWS parameter store + } else if (awsParameterStoreSecretsObj[key].Value !== secrets[key].value) { + // case: secret value doesn't match one in AWS parameter store + // -> update secret + await ssm + .putParameter({ + Name: `${integration.path}${key}`, + Type: "SecureString", + Value: secrets[key].value, + Overwrite: true + }) + .promise(); + } + }) + ); // Identify secrets to delete - Object.keys(awsParameterStoreSecretsObj).map(async (key) => { - if (!(key in secrets)) { - // case: - // -> delete secret - await ssm - .deleteParameter({ - Name: awsParameterStoreSecretsObj[key].Name - }) - .promise(); - } - }); + await Promise.all( + Object.keys(awsParameterStoreSecretsObj).map(async (key) => { + if (!(key in secrets)) { + // case: + // -> delete secret + await ssm + .deleteParameter({ + Name: awsParameterStoreSecretsObj[key].Name as string + }) + .promise(); + } + }) + ); AWS.config.update({ region: undefined, @@ -564,7 +568,7 @@ const syncSecretsAWSSecretManager = async ({ }) ); - let awsSecretManagerSecretObj: { [key: string]: any } = {}; + let awsSecretManagerSecretObj: { [key: string]: AWS.SecretsManager } = {}; if (awsSecretManagerSecret?.SecretString) { awsSecretManagerSecretObj = JSON.parse(awsSecretManagerSecret.SecretString); @@ -680,15 +684,18 @@ const syncSecretsVercel = async ({ : {}) }; - const vercelSecrets: VercelSecret[] = ( - await request.get(`${IntegrationUrls.VERCEL_API_URL}/v9/projects/${integration.app}/env`, { - params, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + const vercelSecrets = ( + await request.get<{ envs: VercelSecret[] }>( + `${IntegrationUrls.VERCEL_API_URL}/v9/projects/${integration.app}/env`, + { + params, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }) - ).data.envs.filter((secret: VercelSecret) => { + ) + ).data.envs.filter((secret) => { if (!secret.target.includes(integration.targetEnvironment as string)) { // case: secret does not have the same target environment return false; @@ -866,7 +873,7 @@ const syncSecretsNetlify = async ({ }); const res = ( - await request.get( + await request.get( `${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env`, { params: getParams, @@ -877,11 +884,11 @@ const syncSecretsNetlify = async ({ } ) ).data.reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.key]: secret }), - {} + {} as Record ); const newSecrets: NetlifySecret[] = []; // createEnvVars @@ -905,16 +912,16 @@ const syncSecretsNetlify = async ({ } else { // case: Infisical secret exists in Netlify const contexts = res[key].values.reduce( - (obj: any, value: NetlifyValue) => ({ + (obj, value) => ({ ...obj, [value.context]: value }), - {} + {} as Record ); if ((integration.targetEnvironment as string) in contexts) { // case: Netlify secret value exists in integration context - if (secrets[key] !== contexts[integration.targetEnvironment as string].value) { + if (secrets[key].value !== contexts[integration.targetEnvironment as string].value) { // case: Infisical and Netlify secret values are different // -> update Netlify secret context and value updateSecrets.push({ @@ -994,62 +1001,63 @@ const syncSecretsNetlify = async ({ } if (updateSecrets.length > 0) { - updateSecrets.forEach(async (secret: NetlifySecret) => { - await request.patch( - `${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}`, - { - context: secret.values[0].context, - value: secret.values[0].value - }, - { - params: syncParams, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + await Promise.all( + updateSecrets.map(async (secret: NetlifySecret) => { + await request.patch( + `${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}`, + { + context: secret.values[0].context, + value: secret.values[0].value + }, + { + params: syncParams, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - } - ); - }); + ); + }) + ); } if (deleteSecrets.length > 0) { - deleteSecrets.forEach(async (key: string) => { - await request.delete( - `${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${key}`, - { - params: syncParams, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + await Promise.all( + deleteSecrets.map(async (key: string) => { + await request.delete( + `${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${key}`, + { + params: syncParams, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - } - ); - }); + ); + }) + ); } if (deleteSecretValues.length > 0) { - deleteSecretValues.forEach(async (secret: NetlifySecret) => { - await request.delete( - `${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}/value/${secret.values[0].id}`, - { - params: syncParams, - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + await Promise.all( + deleteSecretValues.map(async (secret: NetlifySecret) => { + await request.delete( + `${IntegrationUrls.NETLIFY_API_URL}/api/v1/accounts/${integrationAuth.accountId}/env/${secret.key}/value/${secret.values[0].id}`, + { + params: syncParams, + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - } - ); - }); + ); + }) + ); } }; /** * Sync/push [secrets] to GitHub repo with name [integration.app] - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {TIntegrationAuth} obj.integrationAuth - integration auth details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessToken - access token for GitHub integration */ const syncSecretsGitHub = async ({ integration, @@ -1096,7 +1104,7 @@ const syncSecretsGitHub = async ({ repo: integration.app as string }) ).data.secrets.reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.name]: secret }), @@ -1121,46 +1129,46 @@ const syncSecretsGitHub = async ({ {} ); - Object.keys(encryptedSecrets).map(async (key) => { - if (!(key in secrets)) { - await octokit.request("DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}", { - owner: integration.owner as string, - repo: integration.app as string, - secret_name: key + await Promise.all( + Object.keys(encryptedSecrets).map(async (key) => { + if (!(key in secrets)) { + return octokit.request("DELETE /repos/{owner}/{repo}/actions/secrets/{secret_name}", { + owner: integration.owner as string, + repo: integration.app as string, + secret_name: key + }); + } + }) + ); + + await Promise.all( + Object.keys(secrets).map((key) => { + // let encryptedSecret; + return sodium.ready.then(async () => { + // convert secret & base64 key to Uint8Array. + const binkey = sodium.from_base64(repoPublicKey.key, sodium.base64_variants.ORIGINAL); + const binsec = sodium.from_string(secrets[key].value); + + // encrypt secret using libsodium + const encBytes = sodium.crypto_box_seal(binsec, binkey); + + // convert encrypted Uint8Array to base64 + const encryptedSecret = sodium.to_base64(encBytes, sodium.base64_variants.ORIGINAL); + + await octokit.request("PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}", { + owner: integration.owner as string, + repo: integration.app as string, + secret_name: key, + encrypted_value: encryptedSecret, + key_id: repoPublicKey.key_id + }); }); - } - }); - - Object.keys(secrets).forEach((key) => { - // let encryptedSecret; - sodium.ready.then(async () => { - // convert secret & base64 key to Uint8Array. - const binkey = sodium.from_base64(repoPublicKey.key, sodium.base64_variants.ORIGINAL); - const binsec = sodium.from_string(secrets[key].value); - - // encrypt secret using libsodium - const encBytes = sodium.crypto_box_seal(binsec, binkey); - - // convert encrypted Uint8Array to base64 - const encryptedSecret = sodium.to_base64(encBytes, sodium.base64_variants.ORIGINAL); - - await octokit.request("PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}", { - owner: integration.owner as string, - repo: integration.app as string, - secret_name: key, - encrypted_value: encryptedSecret, - key_id: repoPublicKey.key_id - }); - }); - }); + }) + ); }; /** * Sync/push [secrets] to Render service with id [integration.appId] - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessToken - access token for Render integration */ const syncSecretsRender = async ({ integration, @@ -1188,10 +1196,6 @@ const syncSecretsRender = async ({ /** * Sync/push [secrets] to Laravel Forge sites with id [integration.appId] - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessToken - access token for Laravel Forge integration */ const syncSecretsLaravelForge = async ({ integration, @@ -1204,13 +1208,11 @@ const syncSecretsLaravelForge = async ({ accessId: string | null; accessToken: string; }) => { - function transformObjectToString(obj: any) { + function transformObjectToString(obj: Record) { let result = ""; - for (const key in obj) { - if (obj.hasOwnPropery(key)) { - result += `${key}=${obj[key].value}\n`; - } - } + Object.keys(obj).forEach((key) => { + result += `${key}=${obj[key].value}\n`; + }); return result; } @@ -1231,10 +1233,6 @@ const syncSecretsLaravelForge = async ({ /** * Sync/push [secrets] to Railway project with id [integration.appId] - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessToken - access token for Railway integration */ const syncSecretsRailway = async ({ integration, @@ -1279,10 +1277,6 @@ const syncSecretsRailway = async ({ /** * Sync/push [secrets] to Fly.io app - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessToken - access token for Render integration */ const syncSecretsFlyio = async ({ integration, @@ -1354,7 +1348,7 @@ const syncSecretsFlyio = async ({ }`; const getSecretsRes = ( - await request.post( + await request.post<{ data: { app: { secrets: FlyioSecret[] } } }>( IntegrationUrls.FLYIO_API_URL, { query: GetSecrets, @@ -1373,8 +1367,8 @@ const syncSecretsFlyio = async ({ ).data.data.app.secrets; const deleteSecretsKeys = getSecretsRes - .filter((secret: FlyioSecret) => !(secret.name in secrets)) - .map((secret: FlyioSecret) => secret.name); + .filter((secret) => !(secret.name in secrets)) + .map((secret) => secret.name); // unset (delete) secrets const DeleteSecrets = `mutation($input: UnsetSecretsInput!) { @@ -1460,7 +1454,7 @@ const syncSecretsCircleCI = async ({ // get secrets from CircleCI const getSecretsRes = ( - await request.get( + await request.get<{ items: { name: string }[] }>( `${IntegrationUrls.CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar`, { headers: { @@ -1472,19 +1466,21 @@ const syncSecretsCircleCI = async ({ ).data?.items; // delete secrets from CircleCI - getSecretsRes.forEach(async (sec: any) => { - if (!(sec.name in secrets)) { - await request.delete( - `${IntegrationUrls.CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar/${sec.name}`, - { - headers: { - "Circle-Token": accessToken, - "Content-Type": "application/json" + await Promise.all( + getSecretsRes.map(async (sec) => { + if (!(sec.name in secrets)) { + return request.delete( + `${IntegrationUrls.CIRCLECI_API_URL}/v2/project/${slug}/${integration.app}/envvar/${sec.name}`, + { + headers: { + "Circle-Token": accessToken, + "Content-Type": "application/json" + } } - } - ); - } - }); + ); + } + }) + ); }; /** @@ -1501,21 +1497,20 @@ const syncSecretsTravisCI = async ({ }) => { // get secrets from travis-ci const getSecretsRes = ( - await request.get( - `${IntegrationUrls.TRAVISCI_API_URL}/settings/env_vars?repository_id=${integration.appId}`, - { - headers: { - Authorization: `token ${accessToken}`, - "Accept-Encoding": "application/json" - } + await request.get<{ + env_vars: { name: string; value: string; repository_id: string; id: string }[]; + }>(`${IntegrationUrls.TRAVISCI_API_URL}/settings/env_vars?repository_id=${integration.appId}`, { + headers: { + Authorization: `token ${accessToken}`, + "Accept-Encoding": "application/json" } - ) + }) ).data?.env_vars.reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.name]: secret }), - {} + {} as Record ); // add secrets @@ -1614,10 +1609,10 @@ const syncSecretsGitLab = async ({ `${gitLabApiUrl}/v4/projects/${integrationAppId}/variables?per_page=100`; while (url) { - const response: any = await request.get(url, { headers }); + const response = await request.get(url, { headers }); allEnvVariables = [...allEnvVariables, ...response.data]; - const linkHeader = response.headers.link; + const linkHeader = response.headers.link as string; const nextLink = linkHeader?.split(",").find((part: string) => part.includes('rel="next"')); if (nextLink) { @@ -1649,7 +1644,7 @@ const syncSecretsGitLab = async ({ }); for await (const key of Object.keys(secrets)) { - const existingSecret = getSecretsRes.find((s: any) => s.key === key); + const existingSecret = getSecretsRes.find((s) => s.key === key); if (!existingSecret) { await request.post( `${gitLabApiUrl}/v4/projects/${integration?.appId}/variables`, @@ -1714,7 +1709,7 @@ const syncSecretsSupabase = async ({ secrets: Record; accessToken: string; }) => { - const { data: getSecretsRes } = await request.get( + const { data: getSecretsRes } = await request.get<{ name: string; value: string }[]>( `${IntegrationUrls.SUPABASE_API_URL}/v1/projects/${integration.appId}/secrets`, { headers: { @@ -1741,8 +1736,7 @@ const syncSecretsSupabase = async ({ } ); - const secretsToDelete: any = []; - getSecretsRes?.forEach((secretObj: any) => { + const secretsToDelete = getSecretsRes?.flatMap((secretObj) => { if ( !(secretObj.name in secrets) && // supbase reserved secret ref: https://supabase.com/docs/guides/functions/secrets#default-secrets @@ -1753,8 +1747,9 @@ const syncSecretsSupabase = async ({ "SUPABASE_URL" ].includes(secretObj.name) ) { - secretsToDelete.push(secretObj.name); + return secretObj.name; } + return []; }); await request.delete( @@ -1788,7 +1783,7 @@ const syncSecretsCheckly = async ({ // sync secrets to checkly group envars let getGroupSecretsRes = ( - await request.get( + await request.get<{ environmentVariables: { key: string; value: string }[] }>( `${IntegrationUrls.CHECKLY_API_URL}/v1/check-groups/${integration.targetServiceId}`, { headers: { @@ -1799,11 +1794,11 @@ const syncSecretsCheckly = async ({ } ) ).data.environmentVariables.reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.key]: secret.value }), - {} + {} as Record ); getGroupSecretsRes = Object.keys(getGroupSecretsRes).reduce( @@ -1846,19 +1841,22 @@ const syncSecretsCheckly = async ({ // sync secrets to checkly global envars let getSecretsRes = ( - await request.get(`${IntegrationUrls.CHECKLY_API_URL}/v1/variables`, { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json", - "X-Checkly-Account": integration.appId + await request.get<{ key: string; value: string }[]>( + `${IntegrationUrls.CHECKLY_API_URL}/v1/variables`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json", + "X-Checkly-Account": integration.appId + } } - }) + ) ).data.reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.key]: secret.value }), - {} + {} as Record ); getSecretsRes = Object.keys(getSecretsRes).reduce( @@ -1901,7 +1899,7 @@ const syncSecretsCheckly = async ({ ); // case: secret exists in checkly // -> update/set secret - } else if (secrets[key] !== getSecretsRes[key]) { + } else if (secrets[key].value !== getSecretsRes[key]) { await request.put( `${IntegrationUrls.CHECKLY_API_URL}/v1/variables/${key}`, { @@ -1951,7 +1949,7 @@ const syncSecretsQovery = async ({ accessToken: string; }) => { const getSecretsRes = ( - await request.get( + await request.get<{ results: { id: string; value: string; key: string }[] }>( `${IntegrationUrls.QOVERY_API_URL}/${integration.scope}/${integration.appId}/environmentVariable`, { headers: { @@ -1961,11 +1959,11 @@ const syncSecretsQovery = async ({ } ) ).data.results.reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.key]: { id: secret.id, value: secret.value } }), - {} + {} as Record ); // add secrets @@ -2042,7 +2040,7 @@ const syncSecretsTerraformCloud = async ({ }) => { // get secrets from Terraform Cloud const getSecretsRes = ( - await request.get( + await request.get<{ data: { attributes: { key: string; value: string }; id: string }[] }>( `${IntegrationUrls.TERRAFORM_CLOUD_API_URL}/api/v2/workspaces/${integration.appId}/vars`, { headers: { @@ -2052,11 +2050,11 @@ const syncSecretsTerraformCloud = async ({ } ) ).data.data.reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.attributes.key]: secret }), - {} + {} as Record ); // create or update secrets on Terraform Cloud @@ -2138,7 +2136,7 @@ const syncSecretsTeamCity = async ({ }: { integrationAuth: TIntegrationAuths; integration: TIntegrations; - secrets: any; + secrets: Record; accessToken: string; }) => { interface TeamCitySecret { @@ -2171,13 +2169,16 @@ const syncSecretsTeamCity = async ({ ) ).data.property .filter((parameter) => !parameter.inherited) - .reduce((obj: any, secret: TeamCitySecret) => { - const secretName = secret.name.replace(/^env\./, ""); - return { - ...obj, - [secretName]: secret.value - }; - }, {}); + .reduce( + (obj, secret) => { + const secretName = secret.name.replace(/^env\./, ""); + return { + ...obj, + [secretName]: secret.value + }; + }, + {} as Record + ); for await (const key of Object.keys(secrets)) { if (!(key in res) || (key in res && secrets[key].value !== res[key])) { @@ -2216,7 +2217,7 @@ const syncSecretsTeamCity = async ({ } else { // case: sync to TeamCity project const res = ( - await request.get( + await request.get<{ property: TeamCitySecret[] }>( `${integrationAuth.url}/app/rest/projects/id:${integration.appId}/parameters`, { headers: { @@ -2225,16 +2226,19 @@ const syncSecretsTeamCity = async ({ } } ) - ).data.property.reduce((obj: any, secret: TeamCitySecret) => { - const secretName = secret.name.replace(/^env\./, ""); - return { - ...obj, - [secretName]: secret.value - }; - }, {}); + ).data.property.reduce( + (obj, secret) => { + const secretName = secret.name.replace(/^env\./, ""); + return { + ...obj, + [secretName]: secret.value + }; + }, + {} as Record + ); for await (const key of Object.keys(secrets)) { - if (!(key in res) || (key in res && secrets[key] !== res[key])) { + if (!(key in res) || (key in res && secrets[key].value !== res[key])) { // case: secret does not exist in TeamCity or secret value has changed // -> create/update secret await request.post( @@ -2347,7 +2351,9 @@ const syncSecretsCloudflarePages = async ({ }) => { // get secrets from cloudflare pages const getSecretsRes = ( - await request.get( + await request.get<{ + result: { deployment_configs: Record }> }; + }>( `${IntegrationUrls.CLOUDFLARE_PAGES_API_URL}/client/v4/accounts/${accessId}/pages/projects/${integration.app}`, { headers: { @@ -2359,21 +2365,12 @@ const syncSecretsCloudflarePages = async ({ ).data.result.deployment_configs[integration.targetEnvironment as string].env_vars; // copy the secrets object, so we can set deleted keys to null - const secretsObj: any = getSecretKeyValuePair(secrets); - - for (const [key, val] of Object.entries(secretsObj)) { - secretsObj[key] = { type: "secret_text", value: val }; - } - - if (getSecretsRes) { - for await (const key of Object.keys(getSecretsRes)) { - if (!(key in secrets)) { - // case: secret does not exist in infisical - // -> delete secret from cloudflare pages - secretsObj[key] = null; - } - } - } + const secretsObj = Object.fromEntries( + Object.entries(getSecretKeyValuePair(secrets)).map(([key, val]) => [ + key, + key in Object.keys(getSecretsRes) ? { type: "secret_text", value: val } : null + ]) + ); const data = { deployment_configs: { @@ -2411,7 +2408,7 @@ const syncSecretsCloudflareWorkers = async ({ }) => { // get secrets from cloudflare workers const getSecretsRes = ( - await request.get( + await request.get<{ result: { name: string }[] }>( `${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets`, { headers: { @@ -2422,33 +2419,36 @@ const syncSecretsCloudflareWorkers = async ({ ) ).data.result; - const secretsObj: any = getSecretKeyValuePair(secrets); - - for (const [key, val] of Object.entries(secretsObj)) { - secretsObj[key] = { type: "secret_text", value: val }; - } + const secretsObj = Object.fromEntries( + Object.entries(getSecretKeyValuePair(secrets)).map(([key, val]) => [ + key, + { type: "secret_text", value: val } + ]) + ); // get deleted secrets list const deletedSecretKeys: string[] = []; if (getSecretsRes) { - getSecretsRes.forEach((secretRes: any) => { + getSecretsRes.forEach((secretRes) => { if (!Object.keys(secrets).includes(secretRes.name)) { deletedSecretKeys.push(secretRes.name); } }); } - deletedSecretKeys.forEach(async (secretKey) => { - await request.delete( - `${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets/${secretKey}`, - { - headers: { - Authorization: `Bearer ${accessToken}`, - Accept: "application/json" + await Promise.all( + deletedSecretKeys.map(async (secretKey) => { + return request.delete( + `${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets/${secretKey}`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: "application/json" + } } - } - ); - }); + ); + }) + ); interface ConvertedSecret { name: string; @@ -2471,27 +2471,24 @@ const syncSecretsCloudflareWorkers = async ({ }) ); - data.forEach(async (secret) => { - await request.put( - `${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets`, - secret, - { - headers: { - Authorization: `Bearer ${accessToken}`, - Accept: "application/json" + await Promise.all( + data.map(async (secret) => { + return request.put( + `${IntegrationUrls.CLOUDFLARE_WORKERS_API_URL}/client/v4/accounts/${accessId}/workers/scripts/${integration.app}/secrets`, + secret, + { + headers: { + Authorization: `Bearer ${accessToken}`, + Accept: "application/json" + } } - } - ); - }); + ); + }) + ); }; /** * Sync/push [secrets] to BitBucket repo with name [integration.app] - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {TIntegrationAuth} obj.integrationAuth - integration auth details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessToken - access token for BitBucket integration */ const syncSecretsBitBucket = async ({ integration, @@ -2700,18 +2697,21 @@ const syncSecretsWindmill = async ({ // get secrets stored in windmill workspace const res = ( - await request.get(`${IntegrationUrls.WINDMILL_API_URL}/w/${integration.appId}/variables/list`, { - headers: { - Authorization: `Bearer ${accessToken}`, - "Accept-Encoding": "application/json" + await request.get( + `${IntegrationUrls.WINDMILL_API_URL}/w/${integration.appId}/variables/list`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + "Accept-Encoding": "application/json" + } } - }) + ) ).data.reduce( - (obj: any, secret: WindmillSecret) => ({ + (obj, secret) => ({ ...obj, [secret.path]: secret }), - {} + {} as Record ); // eslint-disable-next-line @@ -2778,11 +2778,6 @@ const syncSecretsWindmill = async ({ /** * Sync/push [secrets] to Cloud66 application with name [integration.app] - * @param {Object} obj - * @param {TIntegrations} obj.integration - integration details - * @param {TIntegrationAuth} obj.integrationAuth - integration auth details - * @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values) - * @param {String} obj.accessToken - access token for Cloud66 integration */ const syncSecretsCloud66 = async ({ integration, @@ -2802,12 +2797,12 @@ const syncSecretsCloud66 = async ({ updated_at: string; is_password: boolean; is_generated: boolean; - history: any[]; + history: unknown[]; } // get all current secrets const res = ( - await request.get( + await request.get<{ response: Cloud66Secret[] }>( `${IntegrationUrls.CLOUD_66_API_URL}/3/stacks/${integration.appId}/environments`, { headers: { @@ -2817,9 +2812,9 @@ const syncSecretsCloud66 = async ({ } ) ).data.response - .filter((secret: Cloud66Secret) => !secret.readonly || !secret.is_generated) + .filter((secret) => !secret.readonly || !secret.is_generated) .reduce( - (obj: any, secret: any) => ({ + (obj, secret) => ({ ...obj, [secret.key]: secret }), diff --git a/backend/src/services/integration-auth/integration-team.ts b/backend/src/services/integration-auth/integration-team.ts index 287e7cc7a..81ef9b70c 100644 --- a/backend/src/services/integration-auth/integration-team.ts +++ b/backend/src/services/integration-auth/integration-team.ts @@ -1,7 +1,7 @@ import { request } from "@app/lib/config/request"; import { BadRequestError } from "@app/lib/errors"; -import { Integrations,IntegrationUrls } from "./integration-list"; +import { Integrations, IntegrationUrls } from "./integration-list"; type Team = { name: string; @@ -12,7 +12,7 @@ const getTeamsGitLab = async ({ url, accessToken }: { url: string; accessToken: let teams: Team[] = []; const res = ( - await request.get(`${gitLabApiUrl}/v4/groups`, { + await request.get<{ name: string; id: string }[]>(`${gitLabApiUrl}/v4/groups`, { headers: { Authorization: `Bearer ${accessToken}`, "Accept-Encoding": "application/json" @@ -20,7 +20,7 @@ const getTeamsGitLab = async ({ url, accessToken }: { url: string; accessToken: }) ).data; - teams = res.map((t: any) => ({ + teams = res.map((t) => ({ name: t.name, teamId: t.id })); diff --git a/backend/src/services/integration-auth/integration-token.ts b/backend/src/services/integration-auth/integration-token.ts index f67b13a92..3e50e82ae 100644 --- a/backend/src/services/integration-auth/integration-token.ts +++ b/backend/src/services/integration-auth/integration-token.ts @@ -80,8 +80,8 @@ const exchangeCodeGCP = async ({ code }: { code: string }) => { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeGCPResponse = ( - await request.post( + const res = ( + await request.post( IntegrationUrls.GCP_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -108,8 +108,8 @@ const exchangeCodeAzure = async ({ code }: { code: string }) => { if (!appCfg.CLIENT_ID_AZURE || !appCfg.CLIENT_SECRET_AZURE) { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeAzureResponse = ( - await request.post( + const res = ( + await request.post( IntegrationUrls.AZURE_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -118,7 +118,7 @@ const exchangeCodeAzure = async ({ code }: { code: string }) => { client_id: appCfg.CLIENT_ID_AZURE, client_secret: appCfg.CLIENT_SECRET_AZURE, redirect_uri: `${appCfg.SITE_URL}/integrations/azure-key-vault/oauth2/callback` - } as any) + }) ) ).data; @@ -138,8 +138,8 @@ const exchangeCodeHeroku = async ({ code }: { code: string }) => { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeHerokuResponse = ( - await request.post( + const res = ( + await request.post( IntegrationUrls.HEROKU_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -160,12 +160,6 @@ const exchangeCodeHeroku = async ({ code }: { code: string }) => { /** * Return [accessToken], [accessExpiresAt], and [refreshToken] for Vercel * code-token exchange - * @param {Object} obj1 - * @param {Object} obj1.code - code for code-token exchange - * @returns {Object} obj2 - * @returns {String} obj2.accessToken - access token for Heroku API - * @returns {String} obj2.refreshToken - refresh token for Heroku API - * @returns {Date} obj2.accessExpiresAt - date of expiration for access token */ const exchangeCodeVercel = async ({ code }: { code: string }) => { const appCfg = getConfig(); @@ -173,15 +167,15 @@ const exchangeCodeVercel = async ({ code }: { code: string }) => { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeVercelResponse = ( - await request.post( + const res = ( + await request.post( IntegrationUrls.VERCEL_TOKEN_URL, new URLSearchParams({ code, client_id: appCfg.CLIENT_ID_VERCEL, client_secret: appCfg.CLIENT_SECRET_VERCEL, redirect_uri: `${appCfg.SITE_URL}/integrations/vercel/oauth2/callback` - } as any) + }) ) ).data; @@ -196,12 +190,6 @@ const exchangeCodeVercel = async ({ code }: { code: string }) => { /** * Return [accessToken], [accessExpiresAt], and [refreshToken] for Vercel * code-token exchange - * @param {Object} obj1 - * @param {Object} obj1.code - code for code-token exchange - * @returns {Object} obj2 - * @returns {String} obj2.accessToken - access token for Heroku API - * @returns {String} obj2.refreshToken - refresh token for Heroku API - * @returns {Date} obj2.accessExpiresAt - date of expiration for access token */ const exchangeCodeNetlify = async ({ code }: { code: string }) => { const appCfg = getConfig(); @@ -209,8 +197,8 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeNetlifyResponse = ( - await request.post( + const res = ( + await request.post( IntegrationUrls.NETLIFY_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -218,7 +206,7 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => { client_id: appCfg.CLIENT_ID_NETLIFY, client_secret: appCfg.CLIENT_SECRET_NETLIFY, redirect_uri: `${appCfg.SITE_URL}/integrations/netlify/oauth2/callback` - } as any) + }) ) ).data; @@ -230,7 +218,7 @@ const exchangeCodeNetlify = async ({ code }: { code: string }) => { // }); const res3 = ( - await request.get("https://api.netlify.com/api/v1/accounts", { + await request.get>("https://api.netlify.com/api/v1/accounts", { headers: { Authorization: `Bearer ${res.access_token}` } @@ -252,8 +240,8 @@ const exchangeCodeGithub = async ({ code }: { code: string }) => { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeGithubResponse = ( - await request.get(IntegrationUrls.GITHUB_TOKEN_URL, { + const res = ( + await request.get(IntegrationUrls.GITHUB_TOKEN_URL, { params: { client_id: appCfg.CLIENT_ID_GITHUB, client_secret: appCfg.CLIENT_SECRET_GITHUB, @@ -285,8 +273,8 @@ const exchangeCodeGitlab = async ({ code, url }: { code: string; url?: string }) throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeGitlabResponse = ( - await request.post( + const res = ( + await request.post( url ? `${url}/oauth/token` : IntegrationUrls.GITLAB_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -294,7 +282,7 @@ const exchangeCodeGitlab = async ({ code, url }: { code: string; url?: string }) client_id: appCfg.CLIENT_ID_GITLAB, client_secret: appCfg.CLIENT_SECRET_GITLAB, redirect_uri: `${appCfg.SITE_URL}/integrations/gitlab/oauth2/callback` - } as any), + }), { headers: { "Accept-Encoding": "application/json" @@ -324,8 +312,8 @@ const exchangeCodeBitBucket = async ({ code }: { code: string }) => { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const res: ExchangeCodeBitBucketResponse = ( - await request.post( + const res = ( + await request.post( IntegrationUrls.BITBUCKET_TOKEN_URL, new URLSearchParams({ grant_type: "authorization_code", @@ -333,7 +321,7 @@ const exchangeCodeBitBucket = async ({ code }: { code: string }) => { client_id: appCfg.CLIENT_ID_BITBUCKET, client_secret: appCfg.CLIENT_SECRET_BITBUCKET, redirect_uri: `${appCfg.SITE_URL}/integrations/bitbucket/oauth2/callback` - } as any), + }), { headers: { "Accept-Encoding": "application/json" @@ -593,7 +581,7 @@ const exchangeRefreshBitBucket = async ({ refreshToken }: { refreshToken: string client_id: appCfg.CLIENT_ID_BITBUCKET, client_secret: appCfg.CLIENT_SECRET_BITBUCKET, redirect_uri: `${appCfg.SITE_URL}/integrations/bitbucket/oauth2/callback` - } as any), + }), { headers: { "Accept-Encoding": "application/json" @@ -624,7 +612,11 @@ const exchangeRefreshGCPSecretManager = async ({ const accessExpiresAt = new Date(); if (metadata?.authMethod === "serviceAccount") { - const serviceAccount = JSON.parse(refreshToken); + const serviceAccount = JSON.parse(refreshToken) as { + client_email: string; + token_uri: string; + private_key: string; + }; const payload = { iss: serviceAccount.client_email, @@ -663,14 +655,14 @@ const exchangeRefreshGCPSecretManager = async ({ if (!appCfg.CLIENT_SECRET_GCP_SECRET_MANAGER || !appCfg.CLIENT_ID_GCP_SECRET_MANAGER) { throw new BadRequestError({ message: "Missing client id and client secret" }); } - const { data }: { data: RefreshTokenGCPSecretManagerResponse } = await request.post( + const { data } = await request.post( IntegrationUrls.GCP_TOKEN_URL, new URLSearchParams({ client_id: appCfg.CLIENT_ID_GCP_SECRET_MANAGER, client_secret: appCfg.CLIENT_SECRET_GCP_SECRET_MANAGER, refresh_token: refreshToken, grant_type: "refresh_token" - } as any) + }) ); accessExpiresAt.setSeconds(accessExpiresAt.getSeconds() + data.expires_in); diff --git a/backend/src/services/org/org-dal.ts b/backend/src/services/org/org-dal.ts index 51ab59f68..54237f70a 100644 --- a/backend/src/services/org/org-dal.ts +++ b/backend/src/services/org/org-dal.ts @@ -7,7 +7,8 @@ import { TOrganizationsInsert, TOrgMemberships, TOrgMembershipsInsert, - TOrgMembershipsUpdate + TOrgMembershipsUpdate, + TUserEncryptionKeys } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { @@ -40,7 +41,7 @@ export const orgDALFactory = (db: TDbClient) => { `${TableName.OrgMembership}.orgId`, `${TableName.Organization}.id` ) - .select(`${TableName.Organization}.*`); + .select(selectAllTableCols(TableName.Organization)); return org; } catch (error) { throw new DatabaseError({ error, name: "Find all org by user id" }); @@ -50,9 +51,9 @@ export const orgDALFactory = (db: TDbClient) => { const findOrgByProjectId = async (projectId: string): Promise => { try { const [org] = await db(TableName.Project) - .where({ [`${[TableName.Project]}.id`]: projectId }) + .where({ [`${TableName.Project}.id` as "id"]: projectId }) .join(TableName.Organization, `${TableName.Project}.orgId`, `${TableName.Organization}.id`) - .select(`${TableName.Organization}.*`); + .select(selectAllTableCols(TableName.Organization)); return org; } catch (error) { @@ -66,7 +67,7 @@ export const orgDALFactory = (db: TDbClient) => { const members = await db(TableName.OrgMembership) .where({ orgId }) .join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`) - .leftJoin( + .leftJoin( TableName.UserEncryptionKey, `${TableName.UserEncryptionKey}.userId`, `${TableName.Users}.id` @@ -185,16 +186,17 @@ export const orgDALFactory = (db: TDbClient) => { ) => { try { const query = (tx || db)(TableName.OrgMembership) + // eslint-disable-next-line .where(buildFindFilter(filter)) .join(TableName.Users, `${TableName.Users}.id`, `${TableName.OrgMembership}.userId`) .select( selectAllTableCols(TableName.OrgMembership), db.ref("email").withSchema(TableName.Users) ); - if (limit) query.limit(limit); - if (offset) query.offset(offset); + if (limit) void query.limit(limit); + if (offset) void query.offset(offset); if (sort) { - query.orderBy( + void query.orderBy( sort.map(([column, order, nulls]) => ({ column: column as string, order, nulls })) ); } diff --git a/backend/src/services/org/org-service.ts b/backend/src/services/org/org-service.ts index 69772e883..4b0ae357d 100644 --- a/backend/src/services/org/org-service.ts +++ b/backend/src/services/org/org-service.ts @@ -209,7 +209,7 @@ export const orgServiceFactory = ({ * */ const deleteOrganizationById = async (userId: string, orgId: string) => { const { membership } = await permissionService.getUserOrgPermission(userId, orgId); - if (membership.role !== OrgMembershipRole.Admin) + if ((membership.role as OrgMembershipRole) !== OrgMembershipRole.Admin) throw new UnauthorizedError({ name: "Delete org by id", message: "Not an admin" }); const organization = await orgDAL.deleteById(orgId); diff --git a/backend/src/services/project-bot/project-bot-service.ts b/backend/src/services/project-bot/project-bot-service.ts index 8a3fd19d9..4bd80bc21 100644 --- a/backend/src/services/project-bot/project-bot-service.ts +++ b/backend/src/services/project-bot/project-bot-service.ts @@ -43,7 +43,7 @@ export const projectBotServiceFactory = ({ if (!bot.encryptedProjectKeyNonce || !bot.encryptedProjectKey) throw new BadRequestError({ message: "Encryption key missing" }); - if (rootEncryptionKey && bot.keyEncoding === SecretKeyEncoding.BASE64) { + if (rootEncryptionKey && (bot.keyEncoding as SecretKeyEncoding) === SecretKeyEncoding.BASE64) { const privateKeyBot = decryptSymmetric({ iv: bot.iv, tag: bot.tag, @@ -57,7 +57,7 @@ export const projectBotServiceFactory = ({ publicKey: bot.sender.publicKey }); } - if (encryptionKey && bot.keyEncoding === SecretKeyEncoding.UTF8) { + if (encryptionKey && (bot.keyEncoding as SecretKeyEncoding) === SecretKeyEncoding.UTF8) { const privateKeyBot = decryptSymmetric128BitHexKeyUTF8({ iv: bot.iv, tag: bot.tag, diff --git a/backend/src/services/project-env/project-env-dal.ts b/backend/src/services/project-env/project-env-dal.ts index c74e8803c..9b196f08f 100644 --- a/backend/src/services/project-env/project-env-dal.ts +++ b/backend/src/services/project-env/project-env-dal.ts @@ -26,7 +26,7 @@ export const projectEnvDALFactory = (db: TDbClient) => { const findLastEnvPosition = async (projectId: string, tx?: Knex) => { const lastPos = await (tx || db)(TableName.Environment) .where({ projectId }) - .max({ position: "position" }) + .max("position", { as: "position" }) .first(); return lastPos?.position || 0; }; diff --git a/backend/src/services/project-key/project-key-dal.ts b/backend/src/services/project-key/project-key-dal.ts index b183a933b..5cec6014a 100644 --- a/backend/src/services/project-key/project-key-dal.ts +++ b/backend/src/services/project-key/project-key-dal.ts @@ -1,7 +1,7 @@ import { TDbClient } from "@app/db"; import { TableName, TProjectKeys } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; -import { ormify } from "@app/lib/knex"; +import { ormify, selectAllTableCols } from "@app/lib/knex"; export type TProjectKeyDALFactory = ReturnType; @@ -11,25 +11,23 @@ export const projectKeyDALFactory = (db: TDbClient) => { const findLatestProjectKey = async ( userId: string, projectId: string - ): Promise => { + ): Promise<(TProjectKeys & { sender: { publicKey: string } }) | undefined> => { try { const projectKey = await db(TableName.ProjectKeys) - .where({ projectId, receiverId: userId }) .join(TableName.Users, `${TableName.ProjectKeys}.senderId`, `${TableName.Users}.id`) .join( TableName.UserEncryptionKey, `${TableName.UserEncryptionKey}.userId`, `${TableName.Users}.id` ) + .where({ projectId, receiverId: userId }) .orderBy("createdAt", "desc", "last") - .select(`${TableName.ProjectKeys}.*`, `${TableName.UserEncryptionKey}.publicKey`) + .select(selectAllTableCols(TableName.ProjectKeys)) + .select(db.ref("publicKey").withSchema(TableName.UserEncryptionKey)) .first(); if (projectKey) { - projectKey.sender = { - publicKey: projectKey.publicKey - }; + return { ...projectKey, sender: { publicKey: projectKey.publicKey } }; } - return projectKey; } catch (error) { throw new DatabaseError({ error, name: "Find latest project key" }); } diff --git a/backend/src/services/project-membership/project-membership-dal.ts b/backend/src/services/project-membership/project-membership-dal.ts index 86cfa55b4..22b9937a9 100644 --- a/backend/src/services/project-membership/project-membership-dal.ts +++ b/backend/src/services/project-membership/project-membership-dal.ts @@ -1,5 +1,5 @@ import { TDbClient } from "@app/db"; -import { TableName } from "@app/db/schemas"; +import { TableName, TUserEncryptionKeys } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify } from "@app/lib/knex"; @@ -14,7 +14,7 @@ export const projectMembershipDALFactory = (db: TDbClient) => { const members = await db(TableName.ProjectMembership) .where({ projectId }) .join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`) - .join( + .join( TableName.UserEncryptionKey, `${TableName.UserEncryptionKey}.userId`, `${TableName.Users}.id` @@ -25,10 +25,10 @@ export const projectMembershipDALFactory = (db: TDbClient) => { db.ref("role").withSchema(TableName.ProjectMembership), db.ref("roleId").withSchema(TableName.ProjectMembership), db.ref("email").withSchema(TableName.Users), + db.ref("publicKey").withSchema(TableName.UserEncryptionKey), db.ref("firstName").withSchema(TableName.Users), db.ref("lastName").withSchema(TableName.Users), - db.ref("id").withSchema(TableName.Users).as("userId"), - db.ref("publicKey").withSchema(TableName.UserEncryptionKey) + db.ref("id").withSchema(TableName.Users).as("userId") ); return members.map(({ email, firstName, lastName, publicKey, ...data }) => ({ ...data, diff --git a/backend/src/services/project-membership/project-membership-service.ts b/backend/src/services/project-membership/project-membership-service.ts index d2b4901a0..a71aab944 100644 --- a/backend/src/services/project-membership/project-membership-service.ts +++ b/backend/src/services/project-membership/project-membership-service.ts @@ -184,7 +184,7 @@ export const projectMembershipServiceFactory = ({ await smtpService.sendMail({ template: SmtpTemplates.WorkspaceInvite, subjectLine: "Infisical workspace invitation", - recipients: orgMembers.map(({ email }) => email).filter(Boolean) as string[], + recipients: orgMembers.map(({ email }) => email).filter(Boolean), substitutions: { inviterFirstName: sender.firstName, inviterEmail: sender.email, diff --git a/backend/src/services/secret-blind-index/secret-blind-index-dal.ts b/backend/src/services/secret-blind-index/secret-blind-index-dal.ts index c508728af..8c492831b 100644 --- a/backend/src/services/secret-blind-index/secret-blind-index-dal.ts +++ b/backend/src/services/secret-blind-index/secret-blind-index-dal.ts @@ -25,8 +25,8 @@ export const secretBlindIndexDALFactory = (db: TDbClient) => { ) .where({ projectId }) .whereNull("secretBlindIndex") - .count(`${TableName.Secret}.id`); - return (doc as any)?.[0]?.count || 0; + .count(`${TableName.Secret}.id` as "id"); + return doc?.[0]?.count || 0; } catch (error) { throw new DatabaseError({ error, name: "CountOfSecretWillNullSecretBlindIndex" }); } diff --git a/backend/src/services/secret-folder/secret-folder-dal.ts b/backend/src/services/secret-folder/secret-folder-dal.ts index 3d25217cb..505f9a957 100644 --- a/backend/src/services/secret-folder/secret-folder-dal.ts +++ b/backend/src/services/secret-folder/secret-folder-dal.ts @@ -42,7 +42,7 @@ const sqlFindMultipleFolderByEnvPathQuery = ( // Thus each node has connection to parent node // for a given path from root we recursively reach to the leaf path or till we get null // the below query is the base case where we select root folder which has parent folder id as null - baseQb + void baseQb .select({ depth: 1, // latestFolderVerId: db.raw("NULL::uuid"), @@ -57,34 +57,35 @@ const sqlFindMultipleFolderByEnvPathQuery = ( formatedQuery.map(({ envId }) => envId) ) .select(selectAllTableCols(TableName.SecretFolder)) - .union((qb) => - // for here on we keep going to next child node. - // we also keep a measure of depth then we check the depth matches the array path segment and folder name - // that is at depth 1 for a path /folder1/folder2 -> the name should be folder1 - qb - .select({ - depth: db.raw("parent.depth + 1"), - path: db.raw( - "CONCAT((CASE WHEN parent.path = '/' THEN '' ELSE parent.path END),'/', secret_folders.name)" - ) - }) - .select(selectAllTableCols(TableName.SecretFolder)) - .where((wb) => - formatedQuery.map(({ secretPath }) => - wb.orWhereRaw( - `depth = array_position(ARRAY[${secretPath - .map(() => "?") - .join(",")}]::varchar[], ${TableName.SecretFolder}.name,depth)`, - [...secretPath] + .union( + (qb) => + // for here on we keep going to next child node. + // we also keep a measure of depth then we check the depth matches the array path segment and folder name + // that is at depth 1 for a path /folder1/folder2 -> the name should be folder1 + void qb + .select({ + depth: db.raw("parent.depth + 1"), + path: db.raw( + "CONCAT((CASE WHEN parent.path = '/' THEN '' ELSE parent.path END),'/', secret_folders.name)" + ) + }) + .select(selectAllTableCols(TableName.SecretFolder)) + .where((wb) => + formatedQuery.map(({ secretPath }) => + wb.orWhereRaw( + `depth = array_position(ARRAY[${secretPath + .map(() => "?") + .join(",")}]::varchar[], ${TableName.SecretFolder}.name,depth)`, + [...secretPath] + ) ) ) - ) - .from(TableName.SecretFolder) - .join("parent", (bd) => - bd - .on("parent.id", `${TableName.SecretFolder}.parentId`) - .andOn("parent.envId", `${TableName.SecretFolder}.envId`) - ) + .from(TableName.SecretFolder) + .join("parent", (bd) => + bd + .on("parent.id", `${TableName.SecretFolder}.parentId`) + .andOn("parent.envId", `${TableName.SecretFolder}.envId`) + ) ); }) .select("*") @@ -113,7 +114,7 @@ const sqlFindFolderByPathQuery = ( // Thus each node has connection to parent node // for a given path from root we recursively reach to the leaf path or till we get null // the below query is the base case where we select root folder which has parent folder id as null - baseQb + void baseQb .select({ depth: 1, // latestFolderVerId: db.raw("NULL::uuid"), @@ -131,26 +132,27 @@ const sqlFindFolderByPathQuery = ( }) .where(`${TableName.Environment}.slug`, environment) .select(selectAllTableCols(TableName.SecretFolder)) - .union((qb) => - // for here on we keep going to next child node. - // we also keep a measure of depth then we check the depth matches the array path segment and folder name - // that is at depth 1 for a path /folder1/folder2 -> the name should be folder1 - qb - .select({ - depth: db.raw("parent.depth + 1"), - path: db.raw( - "CONCAT((CASE WHEN parent.path = '/' THEN '' ELSE parent.path END),'/', secret_folders.name)" + .union( + (qb) => + // for here on we keep going to next child node. + // we also keep a measure of depth then we check the depth matches the array path segment and folder name + // that is at depth 1 for a path /folder1/folder2 -> the name should be folder1 + void qb + .select({ + depth: db.raw("parent.depth + 1"), + path: db.raw( + "CONCAT((CASE WHEN parent.path = '/' THEN '' ELSE parent.path END),'/', secret_folders.name)" + ) + }) + .select(selectAllTableCols(TableName.SecretFolder)) + .whereRaw( + `depth = array_position(ARRAY[${pathSegments + .map(() => "?") + .join(",")}]::varchar[], secret_folders.name,depth)`, + [...pathSegments] ) - }) - .select(selectAllTableCols(TableName.SecretFolder)) - .whereRaw( - `depth = array_position(ARRAY[${pathSegments - .map(() => "?") - .join(",")}]::varchar[], secret_folders.name,depth)`, - [...pathSegments] - ) - .from(TableName.SecretFolder) - .join("parent", "parent.id", `${TableName.SecretFolder}.parentId`) + .from(TableName.SecretFolder) + .join("parent", "parent.id", `${TableName.SecretFolder}.parentId`) ); }) .from("parent") @@ -183,7 +185,7 @@ const sqlFindSecretPathByFolderId = (db: Knex, projectId: string, folderIds: str // first remember our folders are connected as a link list or known as adjacency list // Thus each node has connection to parent node // we first find the folder given in folder id - baseQb + void baseQb .from(TableName.SecretFolder) .select(selectAllTableCols(TableName.SecretFolder)) .select({ @@ -202,24 +204,25 @@ const sqlFindSecretPathByFolderId = (db: Knex, projectId: string, folderIds: str ) .where({ projectId }) .whereIn(`${TableName.SecretFolder}.id`, folderIds) - .union((qb) => - // then we keep going up - // until parent id is null - qb - .select(selectAllTableCols(TableName.SecretFolder)) - .select({ - // then we join join this folder name behind previous as we are going from child to parent - // the root folder check is used to avoid last / and also root name in folders - path: db.raw( - `CONCAT( CASE + .union( + (qb) => + // then we keep going up + // until parent id is null + void qb + .select(selectAllTableCols(TableName.SecretFolder)) + .select({ + // then we join join this folder name behind previous as we are going from child to parent + // the root folder check is used to avoid last / and also root name in folders + path: db.raw( + `CONCAT( CASE WHEN ${TableName.SecretFolder}."parentId" is NULL THEN '' ELSE CONCAT('/', secret_folders.name) END, parent.path )` - ), - child: db.raw("COALESCE(parent.child, parent.id)") - }) - .from(TableName.SecretFolder) - .join("parent", "parent.parentId", `${TableName.SecretFolder}.id`) + ), + child: db.raw("COALESCE(parent.child, parent.id)") + }) + .from(TableName.SecretFolder) + .join("parent", "parent.parentId", `${TableName.SecretFolder}.id`) ); }) .select("*") diff --git a/backend/src/services/secret-folder/secret-folder-version-dal.ts b/backend/src/services/secret-folder/secret-folder-version-dal.ts index b610de359..138450bb3 100644 --- a/backend/src/services/secret-folder/secret-folder-version-dal.ts +++ b/backend/src/services/secret-folder/secret-folder-version-dal.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName,TSecretFolderVersions } from "@app/db/schemas"; +import { TableName, TSecretFolderVersions } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify, selectAllTableCols } from "@app/lib/knex"; diff --git a/backend/src/services/secret-import/secret-import-dal.ts b/backend/src/services/secret-import/secret-import-dal.ts index 0acbd7426..771db02a8 100644 --- a/backend/src/services/secret-import/secret-import-dal.ts +++ b/backend/src/services/secret-import/secret-import-dal.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { TableName,TSecretImports } from "@app/db/schemas"; +import { TableName, TSecretImports } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify } from "@app/lib/knex"; @@ -15,7 +15,7 @@ export const secretImportDALFactory = (db: TDbClient) => { const findLastImportPosition = async (folderId: string, tx?: Knex) => { const lastPos = await (tx || db)(TableName.SecretImport) .where({ folderId }) - .max({ position: "position" }) + .max("position", { as: "position" }) .first(); return lastPos?.position || 0; }; diff --git a/backend/src/services/secret/secret-dal.ts b/backend/src/services/secret/secret-dal.ts index b207f604a..20520bcf2 100644 --- a/backend/src/services/secret/secret-dal.ts +++ b/backend/src/services/secret/secret-dal.ts @@ -63,7 +63,7 @@ export const secretDALFactory = (db: TDbClient) => { .where({ folderId }) .where((bd) => { data.forEach((el) => { - bd.orWhere({ + void bd.orWhere({ secretBlindIndex: el.blindIndex, type: el.type, ...(el.type === SecretType.Personal ? { userId } : {}) @@ -89,7 +89,7 @@ export const secretDALFactory = (db: TDbClient) => { const secs = await (tx || db)(TableName.Secret) .where({ folderId }) .where((bd) => { - bd.whereNull("userId").orWhere({ userId: userId || null }); + void bd.whereNull("userId").orWhere({ userId: userId || null }); }) .leftJoin( TableName.JnSecretTag, @@ -144,7 +144,7 @@ export const secretDALFactory = (db: TDbClient) => { if (el.type === SecretType.Personal && !userId) { throw new BadRequestError({ message: "Missing personal user id" }); } - bd.orWhere({ + void bd.orWhere({ secretBlindIndex: el.blindIndex, type: el.type, userId: el.type === SecretType.Personal ? userId : null diff --git a/backend/src/services/secret/secret-queue.ts b/backend/src/services/secret/secret-queue.ts index 71b2444ae..e633cf431 100644 --- a/backend/src/services/secret/secret-queue.ts +++ b/backend/src/services/secret/secret-queue.ts @@ -318,7 +318,7 @@ export const secretQueueFactory = ({ botKey ); const suffixedSecrets: typeof secrets = {}; - const metadata = integration.metadata as Record; + const metadata = integration.metadata as Record; if (metadata) { Object.keys(secrets).forEach((key) => { const prefix = metadata?.secretPrefix || ""; diff --git a/backend/src/services/smtp/smtp-service.ts b/backend/src/services/smtp/smtp-service.ts index 37c5a98a9..142993ceb 100644 --- a/backend/src/services/smtp/smtp-service.ts +++ b/backend/src/services/smtp/smtp-service.ts @@ -41,8 +41,8 @@ export const getTlsOption = (host?: SmtpHost | string, secure?: boolean) => { if (!secure) return { secure: false }; if (!host) return { secure: true }; - if (host === SmtpHost.Sendgrid) { - return { secure: true, port: 465}; // more details here https://nodemailer.com/smtp/ + if ((host as SmtpHost) === SmtpHost.Sendgrid) { + return { secure: true, port: 465 }; // more details here https://nodemailer.com/smtp/ } if (host.includes("amazonaws.com")) { return { tls: { ciphers: "TLSv1.2" } }; diff --git a/backend/src/services/telemetry/telemetry-service.ts b/backend/src/services/telemetry/telemetry-service.ts index 82e912deb..c386abd95 100644 --- a/backend/src/services/telemetry/telemetry-service.ts +++ b/backend/src/services/telemetry/telemetry-service.ts @@ -51,7 +51,7 @@ To opt into telemetry, you can set "TELEMETRY_ENABLED=true" within the environme } }; - const sendPostHogEvents = async (event: TPostHogEvent) => { + const sendPostHogEvents = (event: TPostHogEvent) => { if (postHog) { postHog.capture({ event: event.event, diff --git a/backend/src/services/webhook/webhook-dal.ts b/backend/src/services/webhook/webhook-dal.ts index 14abcac5a..9e30c9c35 100644 --- a/backend/src/services/webhook/webhook-dal.ts +++ b/backend/src/services/webhook/webhook-dal.ts @@ -74,10 +74,10 @@ export const webhookDALFactory = (db: TDbClient) => { .where(`${TableName.Environment}.projectId`, projectId) .where((qb) => { if (environment) { - qb.where("slug", environment); + void qb.where("slug", environment); } if (secretPath) { - qb.where("secretPath", secretPath); + void qb.where("secretPath", secretPath); } }) .join(TableName.Environment, `${TableName.Webhook}.envId`, `${TableName.Environment}.id`) diff --git a/backend/src/services/webhook/webhook-fns.ts b/backend/src/services/webhook/webhook-fns.ts index a43d1c969..e1445acb6 100644 --- a/backend/src/services/webhook/webhook-fns.ts +++ b/backend/src/services/webhook/webhook-fns.ts @@ -1,5 +1,6 @@ import crypto from "node:crypto"; +import { AxiosError } from "axios"; import picomatch from "picomatch"; import { SecretKeyEncoding, TWebhooks } from "@app/db/schemas"; @@ -111,7 +112,7 @@ export const fnTriggerWebhook = async ({ .filter(({ status }) => status === "rejected") .map((data, i) => ({ id: toBeTriggeredHooks[i].id, - error: data.status === "rejected" && data.reason.message + error: data.status === "rejected" ? (data.reason as AxiosError).message : "" })); await webhookDAL.transaction(async (tx) => {