diff --git a/backend-pg/scripts/generate-schema-types.ts b/backend-pg/scripts/generate-schema-types.ts index 125875a4e..a8e2eaf67 100644 --- a/backend-pg/scripts/generate-schema-types.ts +++ b/backend-pg/scripts/generate-schema-types.ts @@ -35,6 +35,8 @@ const getZodPrimitiveType = (type: string) => { return "z.date()"; case "integer": return "z.number()"; + case "bigint": + return "z.number()"; case "text": return "z.string()"; default: @@ -70,6 +72,10 @@ const getZodDefaultValue = (type: unknown, value: string | number | boolean | Ob if ((value as string).includes("nextval")) return; return `.default(${value})`; } + case "bigint": { + if ((value as string).includes("nextval")) return; + return `.default(${parseInt((value as string).split("::")[0].slice(1, -1), 10)})`; + } case "text": if (typeof value === "string" && value.includes("::")) { return `.default(${value.split("::")[0]})`; diff --git a/backend-pg/src/db/migrations/20231128092347_user-encryption-key.ts b/backend-pg/src/db/migrations/20231128092347_user-encryption-key.ts index 5cf251865..2ac292e88 100644 --- a/backend-pg/src/db/migrations/20231128092347_user-encryption-key.ts +++ b/backend-pg/src/db/migrations/20231128092347_user-encryption-key.ts @@ -10,9 +10,9 @@ export async function up(knex: Knex): Promise { t.text("clientPublicKey"); t.text("serverPrivateKey"); t.integer("encryptionVersion").defaultTo(2); - t.text("protectedKey").notNullable(); - t.text("protectedKeyIV").notNullable(); - t.text("protectedKeyTag").notNullable(); + t.text("protectedKey"); + t.text("protectedKeyIV"); + t.text("protectedKeyTag"); t.text("publicKey").notNullable(); t.text("encryptedPrivateKey").notNullable(); t.text("iv").notNullable(); diff --git a/backend-pg/src/db/migrations/20231228074908_identity-universal-auth.ts b/backend-pg/src/db/migrations/20231228074908_identity-universal-auth.ts index 15270fe94..d594e0ca3 100644 --- a/backend-pg/src/db/migrations/20231228074908_identity-universal-auth.ts +++ b/backend-pg/src/db/migrations/20231228074908_identity-universal-auth.ts @@ -8,9 +8,9 @@ export async function up(knex: Knex): Promise { await knex.schema.createTable(TableName.IdentityUniversalAuth, (t) => { t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); t.string("clientId").notNullable(); - t.integer("accessTokenTTL").defaultTo(7200).notNullable(); - t.integer("accessTokenMaxTTL").defaultTo(7200).notNullable(); - t.integer("accessTokenNumUsesLimit").defaultTo(0).notNullable(); + t.bigInteger("accessTokenTTL").defaultTo(7200).notNullable(); + t.bigInteger("accessTokenMaxTTL").defaultTo(7200).notNullable(); + t.bigInteger("accessTokenNumUsesLimit").defaultTo(0).notNullable(); t.jsonb("clientSecretTrustedIps").notNullable(); t.jsonb("accessTokenTrustedIps").notNullable(); t.timestamps(true, true, true); @@ -25,9 +25,9 @@ export async function up(knex: Knex): Promise { t.string("clientSecretPrefix").notNullable(); t.string("clientSecretHash").notNullable(); t.datetime("clientSecretLastUsedAt"); - t.integer("clientSecretNumUses").defaultTo(0).notNullable(); - t.integer("clientSecretNumUsesLimit").defaultTo(0).notNullable(); - t.integer("clientSecretTTL").defaultTo(0).notNullable(); + t.bigInteger("clientSecretNumUses").defaultTo(0).notNullable(); + t.bigInteger("clientSecretNumUsesLimit").defaultTo(0).notNullable(); + t.bigInteger("clientSecretTTL").defaultTo(0).notNullable(); t.boolean("isClientSecretRevoked").defaultTo(false).notNullable(); t.timestamps(true, true, true); t.uuid("identityUAId").notNullable(); diff --git a/backend-pg/src/db/migrations/20231228075011_identity-access-token.ts b/backend-pg/src/db/migrations/20231228075011_identity-access-token.ts index 1a5953fcd..d0bfbe36a 100644 --- a/backend-pg/src/db/migrations/20231228075011_identity-access-token.ts +++ b/backend-pg/src/db/migrations/20231228075011_identity-access-token.ts @@ -8,10 +8,10 @@ export async function up(knex: Knex): Promise { await knex.schema.createTable(TableName.IdentityAccessToken, (t) => { t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); t.string("authType").notNullable(); - t.integer("accessTokenTTL").defaultTo(2592000).notNullable(); // 30 days second - t.integer("accessTokenMaxTTL").defaultTo(2592000).notNullable(); - t.integer("accessTokenNumUses").defaultTo(0).notNullable(); - t.integer("accessTokenNumUsesLimit").defaultTo(0).notNullable(); + t.bigInteger("accessTokenTTL").defaultTo(2592000).notNullable(); // 30 days second + t.bigInteger("accessTokenMaxTTL").defaultTo(2592000).notNullable(); + t.bigInteger("accessTokenNumUses").defaultTo(0).notNullable(); + t.bigInteger("accessTokenNumUsesLimit").defaultTo(0).notNullable(); t.datetime("accessTokenLastUsedAt"); t.datetime("accessTokenLastRenewedAt"); t.boolean("isAccessTokenRevoked").defaultTo(false).notNullable(); diff --git a/backend-pg/src/db/schemas/identity-ua-client-secrets.ts b/backend-pg/src/db/schemas/identity-ua-client-secrets.ts index 46b22c496..9d65860a1 100644 --- a/backend-pg/src/db/schemas/identity-ua-client-secrets.ts +++ b/backend-pg/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/pg-migrator/package-lock.json b/pg-migrator/package-lock.json index e86d82d5c..5db0d9368 100644 --- a/pg-migrator/package-lock.json +++ b/pg-migrator/package-lock.json @@ -10,10 +10,12 @@ "license": "ISC", "dependencies": { "@casl/ability": "^6.5.0", + "@sindresorhus/slugify": "^2.2.1", "dotenv": "^16.3.1", "knex": "^3.1.0", "level": "^8.0.0", "mongoose": "^8.0.4", + "nanoid": "^5.0.4", "pg": "^8.11.3", "prompt-sync": "^4.2.0", "uuid": "^9.0.1", @@ -414,6 +416,35 @@ "sparse-bitfield": "^3.0.3" } }, + "node_modules/@sindresorhus/slugify": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-2.2.1.tgz", + "integrity": "sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==", + "dependencies": { + "@sindresorhus/transliterate": "^1.0.0", + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/transliterate": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/transliterate/-/transliterate-1.6.0.tgz", + "integrity": "sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==", + "dependencies": { + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@types/node": { "version": "20.11.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.0.tgz", @@ -683,6 +714,17 @@ "node": ">=6" } }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/esm": { "version": "3.2.25", "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", @@ -1025,6 +1067,23 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/nanoid": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.4.tgz", + "integrity": "sha512-vAjmBf13gsmhXSgBrtIclinISzFFy22WwCYoyilZlsrRXNIHSwgFQ1bEdjRwMT3aoadeIF6HMuDRlOxzfXV8ig==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, "node_modules/napi-macros": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.2.2.tgz", diff --git a/pg-migrator/package.json b/pg-migrator/package.json index 64f431a9d..73f7021bf 100644 --- a/pg-migrator/package.json +++ b/pg-migrator/package.json @@ -18,10 +18,12 @@ }, "dependencies": { "@casl/ability": "^6.5.0", + "@sindresorhus/slugify": "^2.2.1", "dotenv": "^16.3.1", "knex": "^3.1.0", "level": "^8.0.0", "mongoose": "^8.0.4", + "nanoid": "^5.0.4", "pg": "^8.11.3", "prompt-sync": "^4.2.0", "uuid": "^9.0.1", diff --git a/pg-migrator/src/@types/knex.d.ts b/pg-migrator/src/@types/knex.d.ts index 10a9162f7..059a14d16 100644 --- a/pg-migrator/src/@types/knex.d.ts +++ b/pg-migrator/src/@types/knex.d.ts @@ -12,6 +12,7 @@ import { TAuthTokenSessions, TAuthTokenSessionsInsert, TAuthTokenSessionsUpdate, + TAuthTokensInsert, TAuthTokensUpdate, TBackupPrivateKey, TBackupPrivateKeyInsert, @@ -82,23 +83,23 @@ import { TSamlConfigs, TSamlConfigsInsert, TSamlConfigsUpdate, - TSapApprovers, - TSapApproversInsert, - TSapApproversUpdate, - TSaRequestSecrets, - TSaRequestSecretsInsert, - TSaRequestSecretsUpdate, - TSaRequestSecretTags, - TSaRequestSecretTagsInsert, - TSaRequestSecretTagsUpdate, - TSarReviewers, - TSarReviewersInsert, - TSarReviewersUpdate, TSecretApprovalPolicies, + TSecretApprovalPoliciesApprovers, + TSecretApprovalPoliciesApproversInsert, + TSecretApprovalPoliciesApproversUpdate, TSecretApprovalPoliciesInsert, TSecretApprovalPoliciesUpdate, TSecretApprovalRequests, + TSecretApprovalRequestSecretTags, + TSecretApprovalRequestSecretTagsInsert, + TSecretApprovalRequestSecretTagsUpdate, TSecretApprovalRequestsInsert, + TSecretApprovalRequestsReviewers, + TSecretApprovalRequestsReviewersInsert, + TSecretApprovalRequestsReviewersUpdate, + TSecretApprovalRequestsSecrets, + TSecretApprovalRequestsSecretsInsert, + TSecretApprovalRequestsSecretsUpdate, TSecretApprovalRequestsUpdate, TSecretBlindIndexes, TSecretBlindIndexesInsert, @@ -142,6 +143,9 @@ import { TSecretVersions, TSecretVersionsInsert, TSecretVersionsUpdate, + TSecretVersionTagJunction, + TSecretVersionTagJunctionInsert, + TSecretVersionTagJunctionUpdate, TServiceTokens, TServiceTokensInsert, TServiceTokensUpdate, @@ -163,7 +167,6 @@ import { TWebhooks, TWebhooksInsert, TWebhooksUpdate, - TAuthTokensInsert, } from "../schemas"; declare module "knex/types/tables" { @@ -348,30 +351,30 @@ declare module "knex/types/tables" { TSecretApprovalPoliciesInsert, TSecretApprovalPoliciesUpdate >; - [TableName.SapApprover]: Knex.CompositeTableType< - TSapApprovers, - TSapApproversInsert, - TSapApproversUpdate + [TableName.SecretApprovalPolicyApprover]: Knex.CompositeTableType< + TSecretApprovalPoliciesApprovers, + TSecretApprovalPoliciesApproversInsert, + TSecretApprovalPoliciesApproversUpdate >; [TableName.SecretApprovalRequest]: Knex.CompositeTableType< TSecretApprovalRequests, TSecretApprovalRequestsInsert, TSecretApprovalRequestsUpdate >; - [TableName.SarReviewer]: Knex.CompositeTableType< - TSarReviewers, - TSarReviewersInsert, - TSarReviewersUpdate + [TableName.SecretApprovalRequestReviewer]: Knex.CompositeTableType< + TSecretApprovalRequestsReviewers, + TSecretApprovalRequestsReviewersInsert, + TSecretApprovalRequestsReviewersUpdate >; - [TableName.SarSecret]: Knex.CompositeTableType< - TSaRequestSecrets, - TSaRequestSecretsInsert, - TSaRequestSecretsUpdate + [TableName.SecretApprovalRequestSecret]: Knex.CompositeTableType< + TSecretApprovalRequestsSecrets, + TSecretApprovalRequestsSecretsInsert, + TSecretApprovalRequestsSecretsUpdate >; - [TableName.SarSecretTag]: Knex.CompositeTableType< - TSaRequestSecretTags, - TSaRequestSecretTagsInsert, - TSaRequestSecretTagsUpdate + [TableName.SecretApprovalRequestSecretTag]: Knex.CompositeTableType< + TSecretApprovalRequestSecretTags, + TSecretApprovalRequestSecretTagsInsert, + TSecretApprovalRequestSecretTagsUpdate >; [TableName.SecretRotation]: Knex.CompositeTableType< TSecretRotations, @@ -439,5 +442,10 @@ declare module "knex/types/tables" { TSecretTagJunctionInsert, TSecretTagJunctionUpdate >; + [TableName.SecretVersionTag]: Knex.CompositeTableType< + TSecretVersionTagJunction, + TSecretVersionTagJunctionInsert, + TSecretVersionTagJunctionUpdate + >; } } diff --git a/pg-migrator/src/index.ts b/pg-migrator/src/index.ts index 9cf66db37..574cf66e6 100644 --- a/pg-migrator/src/index.ts +++ b/pg-migrator/src/index.ts @@ -5,7 +5,7 @@ import knex, { Knex } from "knex"; import path from "path"; import { Level } from "level"; import { packRules } from "@casl/ability/extra"; -import slugify from '@sindresorhus/slugify'; +import slugify from "@sindresorhus/slugify"; import { APIKeyData, @@ -55,6 +55,12 @@ import { ServerConfig } from "./models/serverConfig"; import { flattenFolders } from "./folder"; import { SecretRotation } from "./models/secretRotation"; +import { customAlphabet } from "nanoid"; + +const SLUG_ALPHABETS = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +export const alphaNumericNanoId = customAlphabet(SLUG_ALPHABETS, 10); + enum SecretEncryptionAlgo { AES_256_GCM = "aes-256-gcm", } @@ -75,9 +81,9 @@ const projectKv = kdb.sublevel(TableName.Project); const migrationCheckPointsKv = kdb.sublevel("CHECK-POINTS"); -export const truncateAndSlugify = (slug: string) : string => { - return slugify(slug.slice(0, ENV_SLUG_LENGTH)) -} +export const truncateAndSlugify = (slug: string): string => { + return slugify(slug.slice(0, ENV_SLUG_LENGTH)); +}; /** * Sorts an array of items into groups. The return value is a map where the keys are @@ -128,30 +134,42 @@ const migrateCollection = async < mongooseCollection: Model; filter?: Record; }) => { - - // check ones that have already been migrated - const migrationCheckPointsKvRes = await migrationCheckPointsKv.get(postgresTableName).catch(() => null) + // check ones that have already been migrated + const migrationCheckPointsKvRes = await migrationCheckPointsKv + .get(postgresTableName) + .catch(() => null); if (migrationCheckPointsKvRes) { - console.log(`Skipping Postgres table '${postgresTableName}' because of check point`) - return + console.log( + `Skipping Postgres table '${postgresTableName}' because of check point`, + ); + return; } // else { // await db(postgresTableName).del() // console.log(`Dropped table named '${postgresTableName}' to start fresh from this point on`) // } - + const mongooseDoc: T[] = []; const pgDoc: Tables[K]["base"][] = []; // pre processed data ready to be inserted into PSQL - console.log("Starting migration of ", mongooseCollection.modelName, " Postgres table name:", postgresTableName); + console.log( + "Starting migration of ", + mongooseCollection.modelName, + " Postgres table name:", + postgresTableName, + ); const totalMongoCount = await mongooseCollection.countDocuments(); console.log("Total documents", totalMongoCount); console.log("Total batches", Math.ceil(totalMongoCount / 1000)); let batch = 1; - for await (const doc of mongooseCollection.find(filter || {}).cursor({ batchSize: 100 })) { + for await (const doc of mongooseCollection + .find(filter || {}) + .cursor({ batchSize: 100 })) { mongooseDoc.push(doc); - const preProcessedData = await preProcessing(doc.toObject({ virtuals: true })); + const preProcessedData = await preProcessing( + doc.toObject({ virtuals: true }), + ); if (preProcessedData) { if (Array.isArray(preProcessedData)) { pgDoc.push( @@ -201,16 +219,21 @@ const migrateCollection = async < pgDoc.splice(0, pgDoc.length); } - migrationCheckPointsKv.put(postgresTableName, "done") + migrationCheckPointsKv.put(postgresTableName, "done"); - console.log("Finished migration of ", mongooseCollection.modelName, " Postgres table name:", postgresTableName); + console.log( + "Finished migration of ", + mongooseCollection.modelName, + " Postgres table name:", + postgresTableName, + ); }; const main = async () => { try { dotenv.config(); - process.env.START_FRESH = "true"; + process.env.START_FRESH = "true"; const prompt = promptSync({ sigint: true }); @@ -241,7 +264,7 @@ const main = async () => { await db.raw("select 1+1 as result"); if (process.env.START_FRESH === "true") { - await migrationCheckPointsKv.clear() + await migrationCheckPointsKv.clear(); console.log("Starting rolling back to latest, comment this out later"); await db.migrate.rollback({}, true); @@ -251,7 +274,7 @@ const main = async () => { console.log("Executing migration"); await db.migrate.latest(); console.log("Completed migration"); - } + } const userKv = kdb.sublevel(TableName.Users); await migrateCollection({ @@ -322,7 +345,7 @@ const main = async () => { const id = uuidV4(); const userId = await userKv.get(doc.user.toString()).catch(() => null); - if (!userId) return + if (!userId) return; return { id, @@ -352,6 +375,7 @@ const main = async () => { return { id, name: doc.name, + slug: slugify(`${doc.name}-${alphaNumericNanoId(4)}`), customerId: doc.customerId, createdAt: new Date(doc.createdAt), updatedAt: new Date(doc.updatedAt), @@ -369,7 +393,9 @@ const main = async () => { preProcessing: async (doc) => { const id = uuidV4(); - const orgId = doc?.organization ? await orgKv.get(doc.organization.toString()).catch(() => null) : null; + const orgId = doc?.organization + ? await orgKv.get(doc.organization.toString()).catch(() => null) + : null; if (!orgId) return; await orgRoleKv.put(doc._id.toString(), id); @@ -395,11 +421,15 @@ const main = async () => { returnKeys: ["id"], preProcessing: async (doc) => { const id = uuidV4(); - - const orgId = doc?.organization ? await orgKv.get(doc.organization.toString()).catch(() => null) : null; + + const orgId = doc?.organization + ? await orgKv.get(doc.organization.toString()).catch(() => null) + : null; if (!orgId) return; - const userId = doc?.user ? await userKv.get(doc.user.toString()).catch(() => null) : null; + const userId = doc?.user + ? await userKv.get(doc.user.toString()).catch(() => null) + : null; if (!userId) return; const roleId = doc.customRole @@ -427,10 +457,12 @@ const main = async () => { returnKeys: ["id"], preProcessing: async (doc) => { const id = uuidV4(); - - const orgId = doc?.organization ? await orgKv.get(doc.organization.toString()).catch(() => null) : null; + + const orgId = doc?.organization + ? await orgKv.get(doc.organization.toString()).catch(() => null) + : null; if (!orgId) return; - + return { id, email: doc.email, @@ -448,9 +480,9 @@ const main = async () => { returnKeys: ["id"], preProcessing: async (doc) => { const id = uuidV4(); - + const userId = await userKv.get(doc.user.toString()).catch(() => null); - if (!userId) return + if (!userId) return; return { id, @@ -486,9 +518,9 @@ const main = async () => { returnKeys: ["id"], preProcessing: async (doc) => { const id = uuidV4(); - + const userId = await userKv.get(doc.user.toString()).catch(() => null); - if (!userId) return + if (!userId) return; // expired tokens can be removed if (new Date(doc.expiresAt) < new Date()) return; @@ -511,17 +543,19 @@ const main = async () => { postgresTableName: TableName.Project, returnKeys: ["id"], preProcessing: async (doc) => { - - const orgId = doc?.organization ? await orgKv.get(doc.organization.toString()).catch(() => null ) : null; + const orgId = doc?.organization + ? await orgKv.get(doc.organization.toString()).catch(() => null) + : null; if (!orgId) return; - - await projectKv.put(doc._id.toString(),doc._id.toString()); + + await projectKv.put(doc._id.toString(), doc._id.toString()); // expired tokens can be removed // cannot use this uuid for the org id return { id: doc._id.toString(), name: doc.name.slice(0, 60), + slug: slugify(`${doc.name.slice(0, 60)}-${alphaNumericNanoId(4)}`), orgId, autoCapitalization: doc.autoCapitalization, createdAt: new Date(), @@ -544,11 +578,15 @@ const main = async () => { return envKv.sublevel(environment); }; - const checkIfFolderIsDangling = async (projectId: string, env_slug: string, folderId: string) => { + const checkIfFolderIsDangling = async ( + projectId: string, + env_slug: string, + folderId: string, + ) => { const kv = getFolderKv(projectId, truncateAndSlugify(env_slug)); - const result = await kv.get(`${folderId}:dead`).catch(() => null) - return Boolean(result) - } + const result = await kv.get(`${folderId}:dead`).catch(() => null); + return Boolean(result); + }; await migrateCollection({ db, @@ -556,30 +594,36 @@ const main = async () => { postgresTableName: TableName.Environment, returnKeys: ["id"], preProcessing: async (doc) => { - const orgId = doc?.organization ? await orgKv.get(doc.organization.toString()).catch(() => null ) : null; + const orgId = doc?.organization + ? await orgKv.get(doc.organization.toString()).catch(() => null) + : null; if (!orgId) return; - const projectKvRes = await projectKv.get(doc._id.toString()).catch(() => null); - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc._id.toString()) + .catch(() => null); + if (!projectKvRes) return; // to we scope environments into each project then map each slug with respective id const envKv = envPKv.sublevel(doc._id.toString()); - + // expired tokens can be removed // cannot use this uuid for the org id - return Promise.all(doc.environments.map(async (env, index) => { - const id = uuidV4(); - await envKv.put(truncateAndSlugify(env.slug), id); - return { - id, - name: env.name, - slug: truncateAndSlugify(env.slug), - position: index + 1, - projectId: doc._id.toString(), - createdAt: new Date(), - updatedAt: new Date(), - }; - })); + return Promise.all( + doc.environments.map(async (env, index) => { + const id = uuidV4(); + await envKv.put(truncateAndSlugify(env.slug), id); + return { + id, + name: env.name, + slug: truncateAndSlugify(env.slug), + position: index + 1, + projectId: doc._id.toString(), + createdAt: new Date(), + updatedAt: new Date(), + }; + }), + ); }, }); @@ -590,16 +634,23 @@ const main = async () => { postgresTableName: TableName.SecretFolder, returnKeys: ["id"], preProcessing: async (doc) => { - const orgId = doc?.organization ? await orgKv.get(doc.organization.toString()).catch(() => null ) : null; + const orgId = doc?.organization + ? await orgKv.get(doc.organization.toString()).catch(() => null) + : null; if (!orgId) return; return Promise.all( doc.environments.map(async (env) => { - const id = uuidV4(); - const envId = await getEnvId(doc._id.toString(), truncateAndSlugify(env.slug)); + const envId = await getEnvId( + doc._id.toString(), + truncateAndSlugify(env.slug), + ); - const folderKv = getFolderKv(doc._id.toString(), truncateAndSlugify(env.slug)); + const folderKv = getFolderKv( + doc._id.toString(), + truncateAndSlugify(env.slug), + ); await folderKv.put("root", id); return { id, @@ -610,8 +661,8 @@ const main = async () => { updatedAt: new Date(), }; }), - ) - } + ); + }, }); await migrateCollection({ @@ -623,15 +674,21 @@ const main = async () => { // expired tokens can be removed // cannot use this uuid for the org id - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null); - if(!projectKvRes) return ; + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; const id = uuidV4(); - - const senderId = (await userKv.get(doc.sender.toString()).catch(() => null)); + + const senderId = await userKv + .get(doc.sender.toString()) + .catch(() => null); if (!senderId) return; - - const receiverId = await userKv.get(doc.receiver.toString()).catch(() => null); + + const receiverId = await userKv + .get(doc.receiver.toString()) + .catch(() => null); if (!receiverId) return; return { @@ -658,8 +715,10 @@ const main = async () => { preProcessing: async (doc) => { const id = uuidV4(); - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; await projectRoleKv.put(doc._id.toString(), id); return { @@ -685,13 +744,15 @@ const main = async () => { returnKeys: ["id"], preProcessing: async (doc) => { const id = uuidV4(); - - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return - + + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; + const userId = await userKv.get(doc.user.toString()).catch(() => null); - if (!userId) return - + if (!userId) return; + const roleId = doc.customRole ? await projectRoleKv.get(doc.customRole.toString()) : null; @@ -715,15 +776,23 @@ const main = async () => { postgresTableName: TableName.SecretFolder, returnKeys: ["id"], preProcessing: async (doc) => { - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; - const folderKv = getFolderKv(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const folderKv = getFolderKv( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); - const envId = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const envId = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); const folders = flattenFolders(doc.nodes); - if (!folders) return + if (!folders) return; const pgFolder = await Promise.all( folders @@ -758,18 +827,26 @@ const main = async () => { postgresTableName: TableName.SecretFolderVersion, returnKeys: ["id"], preProcessing: async (doc) => { - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; - const folderKv = getFolderKv(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const folderKv = getFolderKv( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); - // looping through env, we can come across envs that do not exist in the present state. - // This is because some folder snap shots were taken when that env slug exists but the same env slug was later deleted - let envId: string + // looping through env, we can come across envs that do not exist in the present state. + // This is because some folder snap shots were taken when that env slug exists but the same env slug was later deleted + let envId: string; try { - envId = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)); - }catch(e){ - return + envId = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); + } catch (e) { + return; } const rootFolders = (doc?.nodes?.children || []).map( @@ -784,18 +861,18 @@ const main = async () => { rootFolders.map(async (folder) => { const { name, version } = folder; const id = uuidV4(); - + await folderKv.put(getFolderVersionKey(folder.id, version), id); - // we are looking for each folder in folder versions and some we might not see - // because folderKv is ony keeps track of folders that are present in dashboard. So those we don't find, we'll add to same kv but add prefix `dead`. - // This way, we can handle dead ones we encounter in the future + // we are looking for each folder in folder versions and some we might not see + // because folderKv is ony keeps track of folders that are present in dashboard. So those we don't find, we'll add to same kv but add prefix `dead`. + // This way, we can handle dead ones we encounter in the future const folderId = await folderKv.get(folder.id).catch(async () => { const newFolderId = uuidV4(); - await folderKv.put(`${folder.id}:dead`, id) // we are adding dead folders that are not present in dashboard - return newFolderId + await folderKv.put(`${folder.id}:dead`, id); // we are adding dead folders that are not present in dashboard + return newFolderId; }); - + return { name, version, @@ -818,40 +895,55 @@ const main = async () => { postgresTableName: TableName.SecretImport, returnKeys: ["id"], preProcessing: async (doc) => { - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; const envKv = envPKv.sublevel(doc.workspace.toString()); - const folderKv = getFolderKv(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const folderKv = getFolderKv( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); - if (await checkIfFolderIsDangling(doc.workspace.toString(), truncateAndSlugify(doc.environment), doc.folderId)){ - return + if ( + await checkIfFolderIsDangling( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + doc.folderId, + ) + ) { + return; } // case: when import is created for a given folder and later the folder is deleted AND the import with that folder ref is not deleted THEN this folder won't exist?? :( const folderId = await folderKv.get(doc.folderId).catch(() => null); - if (!folderId) return + if (!folderId) return; return Promise.all( - doc.imports.map(async ({ environment, secretPath }, index) => { - const id = uuidV4(); - // case: when import is created but later the env slug is deleted HOWEVER the import with that env slug was not deleted :( - const importEnv = await envKv.get(truncateAndSlugify(environment)).catch(() => null); - if (!importEnv) return + doc.imports + .map(async ({ environment, secretPath }, index) => { + const id = uuidV4(); + // case: when import is created but later the env slug is deleted HOWEVER the import with that env slug was not deleted :( + const importEnv = await envKv + .get(truncateAndSlugify(environment)) + .catch(() => null); + if (!importEnv) return; - return { - id, - folderId, - position: index + 1, - version: 1, - createdAt: new Date((doc as any).createdAt), - updatedAt: new Date((doc as any).updatedAt), - importEnv, - importPath: secretPath, - }; - }).filter(Boolean) + return { + id, + folderId, + position: index + 1, + version: 1, + createdAt: new Date((doc as any).createdAt), + updatedAt: new Date((doc as any).updatedAt), + importEnv, + importPath: secretPath, + }; + }) + .filter(Boolean), ); }, }); @@ -868,13 +960,17 @@ const main = async () => { // skip tags that have slugs that are empty if (doc.slug.length < 1) { - return + return; } - - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return - const createdBy = await userKv.get(doc.user.toString()).catch(() => null); + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; + + const createdBy = await userKv + .get(doc.user.toString()) + .catch(() => null); if (!createdBy) return; return { @@ -898,8 +994,10 @@ const main = async () => { preProcessing: async (doc) => { const id = uuidV4(); - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; return { id, @@ -924,31 +1022,49 @@ const main = async () => { preProcessing: async (doc) => { // when env slug is empty if (doc.environment.length < 1) { - return + return; } - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; // case: we forgot to clean up secrets that belong to deleted env slugs - const isEnvFound = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)).catch(() => null) - if (!isEnvFound) return - - const folderKv = getFolderKv(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const isEnvFound = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ).catch(() => null); + if (!isEnvFound) return; - if (await checkIfFolderIsDangling(doc.workspace.toString(), truncateAndSlugify(doc.environment), doc.folder as string)){ - return + const folderKv = getFolderKv( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); + + if ( + await checkIfFolderIsDangling( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + doc.folder as string, + ) + ) { + return; } // Case: if folder id doesn't exist and the root of the folder also doesn;t exist, THEN put the secret at the ROOT const folderId = await folderKv.get(doc.folder || "root").catch(() => { - console.log("secret location unknown, moving secret to root of env_slug/project") - return "root" + console.log( + "secret location unknown, moving secret to root of env_slug/project", + ); + return "root"; }); - const userId = doc.user ? await userKv.get(doc.user.toString()).catch(() => null) : null; - if (!userId) return - + const userId = doc.user + ? await userKv.get(doc.user.toString()).catch(() => null) + : null; + if (!userId) return; + const id = uuidV4(); await secKv.put(doc._id.toString(), id); @@ -991,19 +1107,32 @@ const main = async () => { (doc.tags || [])?.map(async (tagId) => { const id = uuidV4(); - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; // case: we forgot to clean up secrets that belong to deleted env slugs - const isEnvFound = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)).catch(() => null) - if (!isEnvFound) return - - if (await checkIfFolderIsDangling(doc.workspace.toString(), truncateAndSlugify(doc.environment), doc.folder as string)){ - return + const isEnvFound = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ).catch(() => null); + if (!isEnvFound) return; + + if ( + await checkIfFolderIsDangling( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + doc.folder as string, + ) + ) { + return; } - const userId = doc.user ? await userKv.get(doc.user.toString()).catch(() => null) : null; - if (!userId) return + const userId = doc.user + ? await userKv.get(doc.user.toString()).catch(() => null) + : null; + if (!userId) return; const secretId = await secKv.get(doc._id.toString()).catch((e) => { throw e; @@ -1030,43 +1159,67 @@ const main = async () => { postgresTableName: TableName.SecretVersion, returnKeys: ["id"], preProcessing: async (doc) => { - // when env slug is empty if (doc.environment.length < 1) { - return + return; } - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; // case: we forgot to clean up secrets that belong to deleted env slugs - const isEnvFound = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)).catch(() => null) - if (!isEnvFound) return - - const folderKv = getFolderKv(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const isEnvFound = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ).catch(() => null); + if (!isEnvFound) return; - if (await checkIfFolderIsDangling(doc.workspace.toString(), truncateAndSlugify(doc.environment), doc.folder as string)){ - return + const folderKv = getFolderKv( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); + + if ( + await checkIfFolderIsDangling( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + doc.folder as string, + ) + ) { + return; } // Case: if folder id doesn't exist and the root of the folder also doesn;t exist, THEN put the secret at the ROOT - const folderId = await folderKv.get(doc.folder || "root").catch(async () => { - console.log("secret location unknown, moving secret to root of env_slug/project") - return await folderKv.get("root") - }); + const folderId = await folderKv + .get(doc.folder || "root") + .catch(async () => { + console.log( + "secret location unknown, moving secret to root of env_slug/project", + ); + return await folderKv.get("root"); + }); - const envId = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)); - - const userId = doc.user ? await userKv.get(doc.user.toString()).catch(() => null) : null; - if (!userId) return + const envId = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); + + const userId = doc.user + ? await userKv.get(doc.user.toString()).catch(() => null) + : null; + if (!userId) return; const id = uuidV4(); await secVerKv.put(doc._id.toString(), id); - const secretId = await secKv.get(doc.secret.toString()).catch(async (e) =>{ - const newId = uuidV4(); - await secKv.put(`${doc.secret.toString()}:dead`, newId) - return newId; - }); + const secretId = await secKv + .get(doc.secret.toString()) + .catch(async (e) => { + const newId = uuidV4(); + await secKv.put(`${doc.secret.toString()}:dead`, newId); + return newId; + }); // comment and reminder are not saved in secret version of mongo return { @@ -1101,25 +1254,26 @@ const main = async () => { preProcessing: async (doc) => { const id = uuidV4(); - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; await projectBotKv.put(doc._id.toString(), id); // case: skip bots that are inactive (skipped specifically because 6388653a200193a667c7e3f3 has two records, one active one not) let botKey = await BotKey.findOne({ workspace: doc.workspace, - $or: [ - { isActive: true }, - { isActive: false } - ] - }).sort({ isActive: -1 }).lean(); + $or: [{ isActive: true }, { isActive: false }], + }) + .sort({ isActive: -1 }) + .lean(); const senderId = botKey?.sender ? await userKv.get(botKey.sender.toString()).catch(() => null) : null; - if (!senderId) return + if (!senderId) return; return { id, @@ -1151,8 +1305,10 @@ const main = async () => { const id = uuidV4(); await integrationAuthKv.put(doc._id.toString(), id); - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; return { id, @@ -1189,10 +1345,15 @@ const main = async () => { preProcessing: async (doc) => { const id = uuidV4(); - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; - const envId = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const envId = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); const integrationAuthId = await integrationAuthKv.get( doc.integrationAuth.toString(), ); @@ -1229,9 +1390,11 @@ const main = async () => { returnKeys: ["id"], preProcessing: async (doc) => { const id = uuidV4(); - - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; const userId = await userKv.get(doc.user.toString()).catch(() => null); if (!userId) return; @@ -1263,10 +1426,15 @@ const main = async () => { preProcessing: async (doc) => { const id = uuidV4(); - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; - const envId = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const envId = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); return { id, iv: doc.iv, @@ -1402,8 +1570,10 @@ const main = async () => { returnKeys: ["id"], preProcessing: async (doc) => { const id = uuidV4(); - - const orgId = doc?.organization ? await orgKv.get(doc.organization.toString()).catch(() => null) : null; + + const orgId = doc?.organization + ? await orgKv.get(doc.organization.toString()).catch(() => null) + : null; if (!orgId) return; const identityId = await identityKv.get(doc.identity.toString()); @@ -1431,8 +1601,10 @@ const main = async () => { preProcessing: async (doc) => { const id = uuidV4(); - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; const identityId = await identityKv.get(doc.identity.toString()); const roleId = doc.customRole @@ -1460,10 +1632,15 @@ const main = async () => { preProcessing: async (doc) => { const id = uuidV4(); - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; - const envId = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const envId = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); await sapKv.put(doc._id.toString(), id); return { @@ -1484,7 +1661,7 @@ const main = async () => { await migrateCollection({ db, mongooseCollection: SecretApprovalPolicy, - postgresTableName: TableName.SapApprover, + postgresTableName: TableName.SecretApprovalPolicyApprover, returnKeys: ["id"], preProcessing: async (doc) => { const policyId = await sapKv.get(doc._id.toString()); @@ -1515,10 +1692,15 @@ const main = async () => { const id = uuidV4(); await secRotationKv.put(doc._id.toString(), id); - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; - const envId = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const envId = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); return { id, @@ -1570,7 +1752,7 @@ const main = async () => { }, }); - const ssoConfigKv = kdb.sublevel(TableName.SamlConfig) + const ssoConfigKv = kdb.sublevel(TableName.SamlConfig); await migrateCollection({ db, mongooseCollection: SSOConfig, @@ -1578,15 +1760,17 @@ const main = async () => { returnKeys: ["id"], preProcessing: async (doc) => { const id = uuidV4(); - const orgId = doc?.organization ? await orgKv.get(doc.organization.toString()).catch(() => null) : null; + const orgId = doc?.organization + ? await orgKv.get(doc.organization.toString()).catch(() => null) + : null; if (!orgId) return; - // case: when a org has two SSO configs, one with encryptedEntryPoint defined should be taken. Others skipped - if (!doc.encryptedEntryPoint){ - return + // case: when a org has two SSO configs, one with encryptedEntryPoint defined should be taken. Others skipped + if (!doc.encryptedEntryPoint) { + return; } - await ssoConfigKv.put(orgId.toString(), "true") + await ssoConfigKv.put(orgId.toString(), "true"); return { id, @@ -1608,7 +1792,7 @@ const main = async () => { }, }); - const botOrgsProcessed = kdb.sublevel(TableName.OrgBot) + const botOrgsProcessed = kdb.sublevel(TableName.OrgBot); await migrateCollection({ db, mongooseCollection: BotOrg, @@ -1617,21 +1801,25 @@ const main = async () => { preProcessing: async (doc) => { const id = uuidV4(); - const orgId = doc?.organization ? await orgKv.get(doc.organization.toString()).catch(() => null) : null; + const orgId = doc?.organization + ? await orgKv.get(doc.organization.toString()).catch(() => null) + : null; if (!orgId) return; // case: race condition where there are multiple org bots, we only take one - const botOrgsProcessedRes = await botOrgsProcessed.get(orgId).catch(() => null) + const botOrgsProcessedRes = await botOrgsProcessed + .get(orgId) + .catch(() => null); if (botOrgsProcessedRes) { - return + return; } - const ssoConfigRes = await ssoConfigKv.get(orgId).catch(()=> null) + const ssoConfigRes = await ssoConfigKv.get(orgId).catch(() => null); if (!ssoConfigRes) { - return + return; } - await botOrgsProcessed.put(orgId, "true") + await botOrgsProcessed.put(orgId, "true"); return { id, @@ -1661,8 +1849,10 @@ const main = async () => { returnKeys: ["id"], preProcessing: async (doc) => { const id = uuidV4(); - - const orgId = doc?.organization ? await orgKv.get(doc.organization.toString()).catch(() => null) : null; + + const orgId = doc?.organization + ? await orgKv.get(doc.organization.toString()).catch(() => null) + : null; if (!orgId) return; const userId = await userKv.get(doc.user.toString()).catch(() => null); @@ -1673,8 +1863,12 @@ const main = async () => { orgId, userId, sessionId: doc.sessionId, - createdAt: (doc as any)?.createdAt ? new Date((doc as any).createdAt) : new Date(), - updatedAt: (doc as any)?.updatedAt ? new Date((doc as any).updatedAt) : new Date(), + createdAt: (doc as any)?.createdAt + ? new Date((doc as any).createdAt) + : new Date(), + updatedAt: (doc as any)?.updatedAt + ? new Date((doc as any).updatedAt) + : new Date(), }; }, }); @@ -1686,8 +1880,10 @@ const main = async () => { returnKeys: ["id"], preProcessing: async (doc) => { const id = uuidV4(); - - const orgId = doc?.organizationId.toString() ? await orgKv.get(doc.organizationId.toString()).catch(() => null) : null; + + const orgId = doc?.organizationId.toString() + ? await orgKv.get(doc.organizationId.toString()).catch(() => null) + : null; if (!orgId) return; const userId = await userKv.get(doc.user.toString()).catch(() => null); @@ -1698,8 +1894,12 @@ const main = async () => { orgId, userId, installationId: doc.installationId, - createdAt: (doc as any)?.createdAt ? new Date((doc as any).createdAt) : new Date(), - updatedAt: (doc as any)?.updatedAt ? new Date((doc as any).updatedAt) : new Date(), + createdAt: (doc as any)?.createdAt + ? new Date((doc as any).createdAt) + : new Date(), + updatedAt: (doc as any)?.updatedAt + ? new Date((doc as any).updatedAt) + : new Date(), }; }, }); @@ -1712,7 +1912,9 @@ const main = async () => { preProcessing: async (doc) => { const id = uuidV4(); - const orgId = doc?.organization.toString() ? await orgKv.get(doc.organization.toString()).catch(() => null) : null; + const orgId = doc?.organization.toString() + ? await orgKv.get(doc.organization.toString()).catch(() => null) + : null; if (!orgId) return; return { @@ -1759,8 +1961,10 @@ const main = async () => { preProcessing: async (doc) => { const id = uuidV4(); - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; return { id, @@ -1786,24 +1990,41 @@ const main = async () => { const id = uuidV4(); await snapKv.put(doc._id.toString(), id); - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; const envKv = envPKv.sublevel(doc.workspace.toString()); // case: env was deleted but still links snapshot, so we don't need it - if (!await envKv.get(truncateAndSlugify(doc.environment)).catch(() => null)) { - return + if ( + !(await envKv + .get(truncateAndSlugify(doc.environment)) + .catch(() => null)) + ) { + return; } - const folderKv = getFolderKv(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const folderKv = getFolderKv( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); - if (await checkIfFolderIsDangling(doc.workspace.toString(), truncateAndSlugify(doc.environment), doc.folderId)){ - return + if ( + await checkIfFolderIsDangling( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + doc.folderId, + ) + ) { + return; } - - const envId = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const envId = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); // const folderKv = getFolderKv(doc.workspace.toString(), truncateAndSlugify(doc.environment)); const folderId = await folderKv.get(doc.folderId).catch(async () => { // this folder may not exist now in tree then create a new id and assign it @@ -1831,36 +2052,48 @@ const main = async () => { preProcessing: async (doc) => { const snapshotId = await snapKv.get(doc._id.toString()); - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return - + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; const envKv = envPKv.sublevel(doc.workspace.toString()); // case: env was deleted but still links snapshot, so we don't need it - if (!await envKv.get(truncateAndSlugify(doc.environment)).catch(() => null)) { - return + if ( + !(await envKv + .get(truncateAndSlugify(doc.environment)) + .catch(() => null)) + ) { + return; } - const envId = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const envId = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); return Promise.all( - doc.secretVersions.map(async (secVer) => { - const id = uuidV4(); - - // case: for secret versions that have been discarded, skip creating a snapshot for it - const secretVersionId = await secVerKv.get(secVer.toString()).catch(() => null); - if (!secretVersionId) return + doc.secretVersions + .map(async (secVer) => { + const id = uuidV4(); - return { - id, - envId, - snapshotId, - secretVersionId, - createdAt: (doc as any).createdAt, - updatedAt: (doc as any).updatedAt, - }; - }).filter(Boolean), + // case: for secret versions that have been discarded, skip creating a snapshot for it + const secretVersionId = await secVerKv + .get(secVer.toString()) + .catch(() => null); + if (!secretVersionId) return; + + return { + id, + envId, + snapshotId, + secretVersionId, + createdAt: (doc as any).createdAt, + updatedAt: (doc as any).updatedAt, + }; + }) + .filter(Boolean), ); }, }); @@ -1874,23 +2107,40 @@ const main = async () => { preProcessing: async (doc) => { const snapshotId = await snapKv.get(doc._id.toString()); - if (!doc.folderVersion) return + if (!doc.folderVersion) return; - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; // case: we forgot to clean up secrets that belong to deleted env slugs - const isEnvFound = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)).catch(() => null) - if (!isEnvFound) return - - const folderKv = getFolderKv(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const isEnvFound = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ).catch(() => null); + if (!isEnvFound) return; - if (await checkIfFolderIsDangling(doc.workspace.toString(), truncateAndSlugify(doc.environment), doc.folderId)){ - return + const folderKv = getFolderKv( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); + + if ( + await checkIfFolderIsDangling( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + doc.folderId, + ) + ) { + return; } - const envId = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)); - + const envId = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); + const folderVersion = await FolderVersion.findById(doc.folderVersion); if (!folderVersion) return; @@ -1914,7 +2164,6 @@ const main = async () => { }, }); - const sarKv = kdb.sublevel(TableName.SecretApprovalRequest); await migrateCollection({ db, @@ -1924,37 +2173,61 @@ const main = async () => { preProcessing: async (doc) => { const id = uuidV4(); - // case: when the policy has been deleted, the request should also be deleted - const policyId = await sapKv.get(doc.policy.toString()).catch(() => null); - if (!policyId) return + // case: when the policy has been deleted, the request should also be deleted + const policyId = await sapKv + .get(doc.policy.toString()) + .catch(() => null); + if (!policyId) return; - const projectKvRes = await projectKv.get(doc.workspace.toString()).catch(() => null) - if (!projectKvRes) return + const projectKvRes = await projectKv + .get(doc.workspace.toString()) + .catch(() => null); + if (!projectKvRes) return; // case: we forgot to clean up secrets that belong to deleted env slugs - const isEnvFound = await getEnvId(doc.workspace.toString(), truncateAndSlugify(doc.environment)).catch(() => null) - if (!isEnvFound) return - - const folderKv = getFolderKv(doc.workspace.toString(), truncateAndSlugify(doc.environment)); + const isEnvFound = await getEnvId( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ).catch(() => null); + if (!isEnvFound) return; - if (await checkIfFolderIsDangling(doc.workspace.toString(), truncateAndSlugify(doc.environment), doc.folderId)){ - return + const folderKv = getFolderKv( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + ); + + if ( + await checkIfFolderIsDangling( + doc.workspace.toString(), + truncateAndSlugify(doc.environment), + doc.folderId, + ) + ) { + return; } // Case: if folder id doesn't exist and the root of the folder also doesn't exist, THEN put the secret at the ROOT - const folderId = await folderKv.get(doc.folderId || "root").catch(async () => { - console.log(`${TableName.SecretApprovalRequest}: secret location unknown, moving secret to root of env_slug/project`) - return await folderKv.get("root") - }); + const folderId = await folderKv + .get(doc.folderId || "root") + .catch(async () => { + console.log( + `${TableName.SecretApprovalRequest}: secret location unknown, moving secret to root of env_slug/project`, + ); + return await folderKv.get("root"); + }); - // case: when the committer has been removed from Infisical, we should delete all of their requests (past and preset). - const committerId = await projectMembKv.get(doc.committer.toString()).catch(() => null); - if (!committerId) return + // case: when the committer has been removed from Infisical, we should delete all of their requests (past and preset). + const committerId = await projectMembKv + .get(doc.committer.toString()) + .catch(() => null); + if (!committerId) return; await sarKv.put(doc._id.toString(), id); const statusChangeBy = doc.statusChangeBy - ? await projectMembKv.get(doc.statusChangeBy.toString()).catch(() => null) + ? await projectMembKv + .get(doc.statusChangeBy.toString()) + .catch(() => null) : null; return { id, @@ -1978,12 +2251,12 @@ const main = async () => { await migrateCollection({ db, mongooseCollection: SecretApprovalRequest, - postgresTableName: TableName.SarReviewer, + postgresTableName: TableName.SecretApprovalRequestReviewer, returnKeys: ["id"], preProcessing: async (doc) => { const id = uuidV4(); const requestId = await sarKv.get(doc._id.toString()).catch(() => null); - if (!requestId) return + if (!requestId) return; return Promise.all( doc.reviewers.map(async ({ status, member }) => { diff --git a/pg-migrator/src/migrations/20231204092737_organization.ts b/pg-migrator/src/migrations/20231204092737_organization.ts index cc03babb2..8888fd041 100644 --- a/pg-migrator/src/migrations/20231204092737_organization.ts +++ b/pg-migrator/src/migrations/20231204092737_organization.ts @@ -9,13 +9,17 @@ export async function up(knex: Knex): Promise { await knex.schema.createTable(TableName.Organization, (t) => { t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); t.string("name").notNullable(); + t.string("slug").notNullable(); t.string("customerId"); // does not need update trigger we will do it manually t.timestamps(true, true, true); }); await knex.schema.alterTable(TableName.AuthTokens, (t) => { t.uuid("orgId"); - t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE"); + t.foreign("orgId") + .references("id") + .inTable(TableName.Organization) + .onDelete("CASCADE"); }); } // this is a one time function diff --git a/pg-migrator/src/migrations/20231212110939_project.ts b/pg-migrator/src/migrations/20231212110939_project.ts index 24b3d1967..37971f7d8 100644 --- a/pg-migrator/src/migrations/20231212110939_project.ts +++ b/pg-migrator/src/migrations/20231212110939_project.ts @@ -8,9 +8,13 @@ export async function up(knex: Knex): Promise { await knex.schema.createTable(TableName.Project, (t) => { t.string("id", 36).primary().defaultTo(knex.fn.uuid()); t.string("name", 60).notNullable(); + t.string("slug").notNullable(); t.boolean("autoCapitalization").defaultTo(true); t.uuid("orgId").notNullable(); - t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE"); + t.foreign("orgId") + .references("id") + .inTable(TableName.Organization) + .onDelete("CASCADE"); t.timestamps(true, true, true); }); } @@ -23,11 +27,14 @@ export async function up(knex: Knex): Promise { t.string("slug").notNullable(); t.integer("position").notNullable(); t.string("projectId").notNullable(); - t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE"); + t.foreign("projectId") + .references("id") + .inTable(TableName.Project) + .onDelete("CASCADE"); // this will ensure ever env has its position t.unique(["projectId", "position"], { indexName: "env_pos_composite_uniqe", - deferrable: "deferred" + deferrable: "deferred", }); t.timestamps(true, true, true); }); @@ -39,12 +46,21 @@ export async function up(knex: Knex): Promise { t.text("encryptedKey").notNullable(); t.text("nonce").notNullable(); t.uuid("receiverId").notNullable(); - t.foreign("receiverId").references("id").inTable(TableName.Users).onDelete("CASCADE"); + t.foreign("receiverId") + .references("id") + .inTable(TableName.Users) + .onDelete("CASCADE"); t.uuid("senderId"); // if sender is deleted just don't do anything to this record - t.foreign("senderId").references("id").inTable(TableName.Users).onDelete("SET NULL"); + t.foreign("senderId") + .references("id") + .inTable(TableName.Users) + .onDelete("SET NULL"); t.string("projectId").notNullable(); - t.foreign("projectId").references("id").inTable(TableName.Project).onDelete("CASCADE"); + t.foreign("projectId") + .references("id") + .inTable(TableName.Project) + .onDelete("CASCADE"); t.timestamps(true, true, true); }); } diff --git a/pg-migrator/src/schemas/index.ts b/pg-migrator/src/schemas/index.ts index b02cab80a..fe02658f9 100644 --- a/pg-migrator/src/schemas/index.ts +++ b/pg-migrator/src/schemas/index.ts @@ -25,11 +25,11 @@ export * from "./project-keys"; export * from "./project-memberships"; export * from "./project-roles"; export * from "./projects"; -export * from "./sa-request-secret-tags"; -export * from "./sa-request-secrets"; +export * from "./secret-approval-request-secret-tags"; +export * from "./secret-approval-requests-secrets"; export * from "./saml-configs"; -export * from "./sap-approvers"; -export * from "./sar-reviewers"; +export * from "./secret-approval-policies-approvers"; +export * from "./secret-approval-requests-reviewers"; export * from "./secret-approval-policies"; export * from "./secret-approval-requests"; export * from "./secret-blind-indexes"; @@ -53,3 +53,4 @@ export * from "./user-actions"; export * from "./user-encryption-keys"; export * from "./users"; export * from "./webhooks"; +export * from "./secret-version-tag-junction"; diff --git a/pg-migrator/src/schemas/models.ts b/pg-migrator/src/schemas/models.ts index 0fab0665c..eba69f621 100644 --- a/pg-migrator/src/schemas/models.ts +++ b/pg-migrator/src/schemas/models.ts @@ -41,11 +41,11 @@ export enum TableName { IdentityOrgMembership = "identity_org_memberships", IdentityProjectMembership = "identity_project_memberships", SecretApprovalPolicy = "secret_approval_policies", - SapApprover = "sap_approvers", // sap: secret approval policy + SecretApprovalPolicyApprover = "secret_approval_policies_approvers", SecretApprovalRequest = "secret_approval_requests", - SarReviewer = "sar_reviewers", - SarSecret = "sa_request_secrets", - SarSecretTag = "sa_request_secret_tags", + SecretApprovalRequestReviewer = "secret_approval_requests_reviewers", + SecretApprovalRequestSecret = "secret_approval_requests_secrets", + SecretApprovalRequestSecretTag = "secret_approval_request_secret_tags", SecretRotation = "secret_rotations", SecretRotationOutput = "secret_rotation_outputs", SamlConfig = "saml_configs", @@ -54,9 +54,9 @@ export enum TableName { GitAppOrg = "git_app_org", SecretScanningGitRisk = "secret_scanning_git_risks", TrustedIps = "trusted_ips", - // junction tables + // junction tables with tags JnSecretTag = "secret_tag_junction", - JnSecretVersionTag = "secret_version_tag_junction" + SecretVersionTag = "secret_version_tag_junction", } export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt"; @@ -64,7 +64,7 @@ export type TImmutableDBKeys = "id" | "createdAt" | "updatedAt"; export const UserDeviceSchema = z .object({ ip: z.string(), - userAgent: z.string() + userAgent: z.string(), }) .array() .default([]); @@ -72,7 +72,7 @@ export const UserDeviceSchema = z export const ServiceTokenScopes = z .object({ environment: z.string(), - secretPath: z.string().default("/") + secretPath: z.string().default("/"), }) .array(); @@ -80,12 +80,12 @@ export enum OrgMembershipRole { Admin = "admin", Member = "member", NoAccess = "no-access", - Custom = "custom" + Custom = "custom", } export enum OrgMembershipStatus { Invited = "invited", - Accepted = "accepted" + Accepted = "accepted", } export enum ProjectMembershipRole { @@ -93,24 +93,24 @@ export enum ProjectMembershipRole { Member = "member", Custom = "custom", Viewer = "viewer", - NoAccess = "no-access" + NoAccess = "no-access", } export enum SecretEncryptionAlgo { - AES_256_GCM = "aes-256-gcm" + AES_256_GCM = "aes-256-gcm", } export enum SecretKeyEncoding { UTF8 = "utf8", BASE64 = "base64", - HEX = "hex" + HEX = "hex", } export enum SecretType { Shared = "shared", - Personal = "personal" + Personal = "personal", } export enum IdentityAuthMethod { - Univeral = "universal" + Univeral = "universal", } diff --git a/pg-migrator/src/schemas/organizations.ts b/pg-migrator/src/schemas/organizations.ts index e9ff4555f..0aa214a00 100644 --- a/pg-migrator/src/schemas/organizations.ts +++ b/pg-migrator/src/schemas/organizations.ts @@ -10,6 +10,7 @@ import { TImmutableDBKeys } from "./models"; export const OrganizationsSchema = z.object({ id: z.string().uuid(), name: z.string(), + slug: z.string(), customerId: z.string().nullable().optional(), createdAt: z.date(), updatedAt: z.date(), @@ -17,4 +18,6 @@ export const OrganizationsSchema = z.object({ export type TOrganizations = z.infer; export type TOrganizationsInsert = Omit; -export type TOrganizationsUpdate = Partial>; +export type TOrganizationsUpdate = Partial< + Omit +>; diff --git a/pg-migrator/src/schemas/projects.ts b/pg-migrator/src/schemas/projects.ts index f44010674..005e4bbde 100644 --- a/pg-migrator/src/schemas/projects.ts +++ b/pg-migrator/src/schemas/projects.ts @@ -10,6 +10,7 @@ import { TImmutableDBKeys } from "./models"; export const ProjectsSchema = z.object({ id: z.string(), name: z.string(), + slug: z.string(), autoCapitalization: z.boolean().default(true).nullable().optional(), orgId: z.string().uuid(), createdAt: z.date(), diff --git a/pg-migrator/src/schemas/sa-request-secret-tags.ts b/pg-migrator/src/schemas/sa-request-secret-tags.ts deleted file mode 100644 index d0366f125..000000000 --- a/pg-migrator/src/schemas/sa-request-secret-tags.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by automation script, DO NOT EDIT. -// Automated by pulling database and generating zod schema -// To update. Just run npm run generate:schema -// Written by akhilmhdh. - -import { z } from "zod"; - -import { TImmutableDBKeys } from "./models"; - -export const SaRequestSecretTagsSchema = z.object({ - id: z.string().uuid(), - secretId: z.string().uuid(), - tagId: z.string().uuid(), - createdAt: z.date(), - updatedAt: z.date(), -}); - -export type TSaRequestSecretTags = z.infer; -export type TSaRequestSecretTagsInsert = Omit; -export type TSaRequestSecretTagsUpdate = Partial>; diff --git a/pg-migrator/src/schemas/sap-approvers.ts b/pg-migrator/src/schemas/secret-approval-policies-approvers.ts similarity index 50% rename from pg-migrator/src/schemas/sap-approvers.ts rename to pg-migrator/src/schemas/secret-approval-policies-approvers.ts index 65cc0aea0..c6fb75f06 100644 --- a/pg-migrator/src/schemas/sap-approvers.ts +++ b/pg-migrator/src/schemas/secret-approval-policies-approvers.ts @@ -7,7 +7,7 @@ import { z } from "zod"; import { TImmutableDBKeys } from "./models"; -export const SapApproversSchema = z.object({ +export const SecretApprovalPoliciesApproversSchema = z.object({ id: z.string().uuid(), approverId: z.string().uuid(), policyId: z.string().uuid(), @@ -15,6 +15,6 @@ export const SapApproversSchema = z.object({ updatedAt: z.date(), }); -export type TSapApprovers = z.infer; -export type TSapApproversInsert = Omit; -export type TSapApproversUpdate = Partial>; +export type TSecretApprovalPoliciesApprovers = z.infer; +export type TSecretApprovalPoliciesApproversInsert = Omit; +export type TSecretApprovalPoliciesApproversUpdate = Partial>; diff --git a/pg-migrator/src/schemas/secret-approval-request-secret-tags.ts b/pg-migrator/src/schemas/secret-approval-request-secret-tags.ts new file mode 100644 index 000000000..47e11e6a9 --- /dev/null +++ b/pg-migrator/src/schemas/secret-approval-request-secret-tags.ts @@ -0,0 +1,20 @@ +// Code generated by automation script, DO NOT EDIT. +// Automated by pulling database and generating zod schema +// To update. Just run npm run generate:schema +// Written by akhilmhdh. + +import { z } from "zod"; + +import { TImmutableDBKeys } from "./models"; + +export const SecretApprovalRequestSecretTagsSchema = z.object({ + id: z.string().uuid(), + secretId: z.string().uuid(), + tagId: z.string().uuid(), + createdAt: z.date(), + updatedAt: z.date(), +}); + +export type TSecretApprovalRequestSecretTags = z.infer; +export type TSecretApprovalRequestSecretTagsInsert = Omit; +export type TSecretApprovalRequestSecretTagsUpdate = Partial>; diff --git a/pg-migrator/src/schemas/sar-reviewers.ts b/pg-migrator/src/schemas/secret-approval-requests-reviewers.ts similarity index 51% rename from pg-migrator/src/schemas/sar-reviewers.ts rename to pg-migrator/src/schemas/secret-approval-requests-reviewers.ts index a23d5cd75..4ed9b50a1 100644 --- a/pg-migrator/src/schemas/sar-reviewers.ts +++ b/pg-migrator/src/schemas/secret-approval-requests-reviewers.ts @@ -7,7 +7,7 @@ import { z } from "zod"; import { TImmutableDBKeys } from "./models"; -export const SarReviewersSchema = z.object({ +export const SecretApprovalRequestsReviewersSchema = z.object({ id: z.string().uuid(), member: z.string().uuid(), status: z.string(), @@ -16,6 +16,6 @@ export const SarReviewersSchema = z.object({ updatedAt: z.date(), }); -export type TSarReviewers = z.infer; -export type TSarReviewersInsert = Omit; -export type TSarReviewersUpdate = Partial>; +export type TSecretApprovalRequestsReviewers = z.infer; +export type TSecretApprovalRequestsReviewersInsert = Omit; +export type TSecretApprovalRequestsReviewersUpdate = Partial>; diff --git a/pg-migrator/src/schemas/sa-request-secrets.ts b/pg-migrator/src/schemas/secret-approval-requests-secrets.ts similarity index 76% rename from pg-migrator/src/schemas/sa-request-secrets.ts rename to pg-migrator/src/schemas/secret-approval-requests-secrets.ts index b8135a785..2fe6c6692 100644 --- a/pg-migrator/src/schemas/sa-request-secrets.ts +++ b/pg-migrator/src/schemas/secret-approval-requests-secrets.ts @@ -7,7 +7,7 @@ import { z } from "zod"; import { TImmutableDBKeys } from "./models"; -export const SaRequestSecretsSchema = z.object({ +export const SecretApprovalRequestsSecretsSchema = z.object({ id: z.string().uuid(), version: z.number().default(1).nullable().optional(), secretBlindIndex: z.string(), @@ -34,6 +34,6 @@ export const SaRequestSecretsSchema = z.object({ secretVersion: z.string().uuid().nullable().optional(), }); -export type TSaRequestSecrets = z.infer; -export type TSaRequestSecretsInsert = Omit; -export type TSaRequestSecretsUpdate = Partial>; +export type TSecretApprovalRequestsSecrets = z.infer; +export type TSecretApprovalRequestsSecretsInsert = Omit; +export type TSecretApprovalRequestsSecretsUpdate = Partial>;