From 9565ef29d00cd0e4b8a36e300065ee94045c4e49 Mon Sep 17 00:00:00 2001 From: = Date: Sat, 12 Apr 2025 00:36:21 +0530 Subject: [PATCH] feat: update with review changes --- .../secret-approval-request-service.ts | 4 +- .../secret-replication-service.ts | 4 +- .../secret-rotation-v2-service.ts | 10 ++-- .../secret-rotation-queue.ts | 4 +- backend/src/lib/crypto/cache.ts | 2 +- .../secret-import/secret-import-service.ts | 8 +-- .../secret-v2-bridge/secret-v2-bridge-dal.ts | 56 ++++++++++++------- .../secret-v2-bridge-service.ts | 16 +++--- 8 files changed, 59 insertions(+), 45 deletions(-) diff --git a/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts b/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts index 29bf64972..2f340626b 100644 --- a/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts +++ b/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts @@ -119,7 +119,7 @@ type TSecretApprovalRequestServiceFactoryDep = { | "bulkUpdate" | "deleteMany" | "find" - | "cacheInvalidateSecretByProjectId" + | "invalidateSecretCacheByProjectId" >; secretVersionV2BridgeDAL: Pick; secretVersionTagV2BridgeDAL: Pick; @@ -870,7 +870,7 @@ export const secretApprovalRequestServiceFactory = ({ }); } - await secretV2BridgeDAL.cacheInvalidateSecretByProjectId(projectId); + await secretV2BridgeDAL.invalidateSecretCacheByProjectId(projectId); await snapshotService.performSnapshot(folderId); const [folder] = await folderDAL.findSecretPathByFolderIds(projectId, [folderId]); if (!folder) { diff --git a/backend/src/ee/services/secret-replication/secret-replication-service.ts b/backend/src/ee/services/secret-replication/secret-replication-service.ts index 17d218eaf..480e80028 100644 --- a/backend/src/ee/services/secret-replication/secret-replication-service.ts +++ b/backend/src/ee/services/secret-replication/secret-replication-service.ts @@ -52,7 +52,7 @@ type TSecretReplicationServiceFactoryDep = { | "delete" | "upsertSecretReferences" | "transaction" - | "cacheInvalidateSecretByProjectId" + | "invalidateSecretCacheByProjectId" >; secretVersionV2BridgeDAL: Pick< TSecretVersionV2DALFactory, @@ -505,7 +505,7 @@ export const secretReplicationServiceFactory = ({ } }); - await secretV2BridgeDAL.cacheInvalidateSecretByProjectId(projectId); + await secretV2BridgeDAL.invalidateSecretCacheByProjectId(projectId); await secretQueueService.syncSecrets({ projectId, orgId, diff --git a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-service.ts b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-service.ts index 6476349c4..1f55ac526 100644 --- a/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-service.ts +++ b/backend/src/ee/services/secret-rotation-v2/secret-rotation-v2-service.ts @@ -88,7 +88,7 @@ export type TSecretRotationV2ServiceFactoryDep = { folderDAL: Pick; secretV2BridgeDAL: Pick< TSecretV2BridgeDALFactory, - "bulkUpdate" | "insertMany" | "deleteMany" | "upsertSecretReferences" | "find" | "cacheInvalidateSecretByProjectId" + "bulkUpdate" | "insertMany" | "deleteMany" | "upsertSecretReferences" | "find" | "invalidateSecretCacheByProjectId" >; secretVersionV2BridgeDAL: Pick; secretVersionTagV2BridgeDAL: Pick; @@ -515,7 +515,7 @@ export const secretRotationV2ServiceFactory = ({ }); }); - await secretV2BridgeDAL.cacheInvalidateSecretByProjectId(projectId); + await secretV2BridgeDAL.invalidateSecretCacheByProjectId(projectId); await snapshotService.performSnapshot(folder.id); await secretQueueService.syncSecrets({ orgId: connection.orgId, @@ -652,7 +652,7 @@ export const secretRotationV2ServiceFactory = ({ }); if (secretsMappingUpdated) { - await secretV2BridgeDAL.cacheInvalidateSecretByProjectId(projectId); + await secretV2BridgeDAL.invalidateSecretCacheByProjectId(projectId); await snapshotService.performSnapshot(folder.id); await secretQueueService.syncSecrets({ orgId: connection.orgId, @@ -779,7 +779,7 @@ export const secretRotationV2ServiceFactory = ({ } if (deleteSecrets) { - await secretV2BridgeDAL.cacheInvalidateSecretByProjectId(projectId); + await secretV2BridgeDAL.invalidateSecretCacheByProjectId(projectId); await snapshotService.performSnapshot(folder.id); await secretQueueService.syncSecrets({ orgId: connection.orgId, @@ -938,7 +938,7 @@ export const secretRotationV2ServiceFactory = ({ } }); - await secretV2BridgeDAL.cacheInvalidateSecretByProjectId(projectId); + await secretV2BridgeDAL.invalidateSecretCacheByProjectId(projectId); await snapshotService.performSnapshot(folder.id); await secretQueueService.syncSecrets({ orgId: connection.orgId, 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 e3cae64ca..2c6124348 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 @@ -48,7 +48,7 @@ type TSecretRotationQueueFactoryDep = { secretRotationDAL: TSecretRotationDALFactory; projectBotService: Pick; secretDAL: Pick; - secretV2BridgeDAL: Pick; + secretV2BridgeDAL: Pick; secretVersionDAL: Pick; secretVersionV2BridgeDAL: Pick; telemetryService: Pick; @@ -340,7 +340,7 @@ export const secretRotationQueueFactory = ({ ); }); - await secretV2BridgeDAL.cacheInvalidateSecretByProjectId(secretRotation.projectId); + await secretV2BridgeDAL.invalidateSecretCacheByProjectId(secretRotation.projectId); } else { if (!botKey) throw new NotFoundError({ diff --git a/backend/src/lib/crypto/cache.ts b/backend/src/lib/crypto/cache.ts index eafac8712..9f36d360b 100644 --- a/backend/src/lib/crypto/cache.ts +++ b/backend/src/lib/crypto/cache.ts @@ -1,6 +1,6 @@ import crypto from "node:crypto"; -export const getCacheKey = (data: unknown) => +export const generateCacheKeyFromData = (data: unknown) => crypto .createHash("md5") .update(JSON.stringify(data)) diff --git a/backend/src/services/secret-import/secret-import-service.ts b/backend/src/services/secret-import/secret-import-service.ts index 393036eab..6141a37b0 100644 --- a/backend/src/services/secret-import/secret-import-service.ts +++ b/backend/src/services/secret-import/secret-import-service.ts @@ -43,7 +43,7 @@ type TSecretImportServiceFactoryDep = { secretImportDAL: TSecretImportDALFactory; folderDAL: TSecretFolderDALFactory; secretDAL: Pick; - secretV2BridgeDAL: Pick; + secretV2BridgeDAL: Pick; projectBotService: Pick; projectDAL: Pick; projectEnvDAL: TProjectEnvDALFactory; @@ -184,7 +184,7 @@ export const secretImportServiceFactory = ({ }); } - await secretV2BridgeDAL.cacheInvalidateSecretByProjectId(projectId); + await secretV2BridgeDAL.invalidateSecretCacheByProjectId(projectId); return { ...secImport, importEnv }; }; @@ -283,7 +283,7 @@ export const secretImportServiceFactory = ({ return doc; }); - await secretV2BridgeDAL.cacheInvalidateSecretByProjectId(projectId); + await secretV2BridgeDAL.invalidateSecretCacheByProjectId(projectId); return { ...updatedSecImport, importEnv: importedEnv }; }; @@ -358,7 +358,7 @@ export const secretImportServiceFactory = ({ actorId }); - await secretV2BridgeDAL.cacheInvalidateSecretByProjectId(projectId); + await secretV2BridgeDAL.invalidateSecretCacheByProjectId(projectId); return secImport; }; diff --git a/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts b/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts index 148e1e82b..a9c909899 100644 --- a/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts +++ b/backend/src/services/secret-v2-bridge/secret-v2-bridge-dal.ts @@ -5,7 +5,7 @@ import { TDbClient } from "@app/db"; import { ProjectType, SecretsV2Schema, SecretType, TableName, TSecretsV2, TSecretsV2Update } from "@app/db/schemas"; import { TKeyStoreFactory } from "@app/keystore/keystore"; import { getConfig } from "@app/lib/config/env"; -import { getCacheKey } from "@app/lib/crypto/cache"; +import { generateCacheKeyFromData } from "@app/lib/crypto/cache"; import { BadRequestError, DatabaseError, NotFoundError } from "@app/lib/errors"; import { buildFindFilter, @@ -34,7 +34,7 @@ export const SecretDalCacheKeys = { ) => { return `${SecretDalCacheKeys.productKey}:${projectId}:${ TableName.SecretV2 - }-dal:v${version}:find-by-folder-ids:${getCacheKey(cacheKey)}`; + }-dal:v${version}:find-by-folder-ids:${generateCacheKeyFromData(cacheKey)}`; }, findByFolderId: ( projectId: string, @@ -43,13 +43,15 @@ export const SecretDalCacheKeys = { ) => { return `${SecretDalCacheKeys.productKey}:${projectId}:${ TableName.SecretV2 - }-dal:v${version}:find-by-folder-id:${getCacheKey(cacheKey)}`; + }-dal:v${version}:find-by-folder-id:${generateCacheKeyFromData(cacheKey)}`; }, find: (projectId: string, version: number, ...args: Parameters) => { const [filter, opts] = args; delete opts?.tx; delete opts?.useCache; - return `${SecretDalCacheKeys.productKey}:${projectId}:${TableName.SecretV2}-dal:v${version}:find:${getCacheKey({ + return `${SecretDalCacheKeys.productKey}:${projectId}:${ + TableName.SecretV2 + }-dal:v${version}:find:${generateCacheKeyFromData({ filter, opts })}`; @@ -64,10 +66,11 @@ interface TSecretV2DalArg { const SECRET_DAL_TTL = 5 * 60; const SECRET_DAL_VERSION_TTL = 15 * 60; +const MAX_SECRET_CACHE_BYTES = 25 * 1024 * 1024; export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { const secretOrm = ormify(db, TableName.SecretV2); - const cacheInvalidateSecretByProjectId = async (projectId: string) => { + const invalidateSecretCacheByProjectId = async (projectId: string) => { const secretDalVersionKey = SecretDalCacheKeys.getSecretDalVersion(projectId); await keyStore.incrementBy(secretDalVersionKey, 1); await keyStore.setExpiry(secretDalVersionKey, SECRET_DAL_VERSION_TTL); @@ -228,11 +231,14 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { const encryptedComment = el.encryptedComment ? el.encryptedComment.toString("base64") : null; return { ...el, encryptedValue, encryptedComment }; }); - await keyStore.setItemWithExpiry( - SecretDalCacheKeys.find(useCache.projectId, secretDalVersion, filter, opts), - SECRET_DAL_TTL, - JSON.stringify(cachedSecrets) - ); + const cache = JSON.stringify(cachedSecrets); + if (Buffer.byteLength(cache, "utf8") < MAX_SECRET_CACHE_BYTES) { + await keyStore.setItemWithExpiry( + SecretDalCacheKeys.find(useCache.projectId, secretDalVersion, filter, opts), + SECRET_DAL_TTL, + cache + ); + } } return data; @@ -437,11 +443,15 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { const encryptedComment = el.encryptedComment ? el.encryptedComment.toString("base64") : null; return { ...el, encryptedValue, encryptedComment }; }); - await keyStore.setItemWithExpiry( - SecretDalCacheKeys.findByFolderId(projectId, secretDalVersion, dto), - SECRET_DAL_TTL, - JSON.stringify(newCachedSecrets) - ); + const cache = JSON.stringify(newCachedSecrets); + + if (Buffer.byteLength(cache, "utf8") < MAX_SECRET_CACHE_BYTES) { + await keyStore.setItemWithExpiry( + SecretDalCacheKeys.findByFolderId(projectId, secretDalVersion, dto), + SECRET_DAL_TTL, + cache + ); + } } return data; } catch (error) { @@ -696,11 +706,15 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { const encryptedComment = el.encryptedComment ? el.encryptedComment.toString("base64") : null; return { ...el, encryptedValue, encryptedComment }; }); - await keyStore.setItemWithExpiry( - SecretDalCacheKeys.findByFolderIds(projectId, secretDalVersion, dto), - SECRET_DAL_TTL, - JSON.stringify(cachedSecrets) - ); + const cache = JSON.stringify(cachedSecrets); + + if (Buffer.byteLength(cache, "utf8") < MAX_SECRET_CACHE_BYTES) { + await keyStore.setItemWithExpiry( + SecretDalCacheKeys.findByFolderIds(projectId, secretDalVersion, dto), + SECRET_DAL_TTL, + cache + ); + } } return data; @@ -895,6 +909,6 @@ export const secretV2BridgeDALFactory = ({ db, keyStore }: TSecretV2DalArg) => { countByFolderIds, findOne, find, - cacheInvalidateSecretByProjectId + invalidateSecretCacheByProjectId }; }; diff --git a/backend/src/services/secret-v2-bridge/secret-v2-bridge-service.ts b/backend/src/services/secret-v2-bridge/secret-v2-bridge-service.ts index fd9bcc4a5..596ebb5a1 100644 --- a/backend/src/services/secret-v2-bridge/secret-v2-bridge-service.ts +++ b/backend/src/services/secret-v2-bridge/secret-v2-bridge-service.ts @@ -331,7 +331,7 @@ export const secretV2BridgeServiceFactory = ({ return createdSecret; }); - await secretDAL.cacheInvalidateSecretByProjectId(projectId); + await secretDAL.invalidateSecretCacheByProjectId(projectId); if (inputSecret.type === SecretType.Shared) { await snapshotService.performSnapshot(folderId); await secretQueueService.syncSecrets({ @@ -540,7 +540,7 @@ export const secretV2BridgeServiceFactory = ({ projectId }); - await secretDAL.cacheInvalidateSecretByProjectId(projectId); + await secretDAL.invalidateSecretCacheByProjectId(projectId); if (inputSecret.type === SecretType.Shared) { await snapshotService.performSnapshot(folderId); await secretQueueService.syncSecrets({ @@ -649,7 +649,7 @@ export const secretV2BridgeServiceFactory = ({ }) ); - await secretDAL.cacheInvalidateSecretByProjectId(projectId); + await secretDAL.invalidateSecretCacheByProjectId(projectId); if (inputSecret.type === SecretType.Shared) { await snapshotService.performSnapshot(folderId); await secretQueueService.syncSecrets({ @@ -1552,7 +1552,7 @@ export const secretV2BridgeServiceFactory = ({ tx }) ); - await secretDAL.cacheInvalidateSecretByProjectId(projectId); + await secretDAL.invalidateSecretCacheByProjectId(projectId); await snapshotService.performSnapshot(folderId); await secretQueueService.syncSecrets({ actor, @@ -1892,7 +1892,7 @@ export const secretV2BridgeServiceFactory = ({ } }); - await secretDAL.cacheInvalidateSecretByProjectId(projectId); + await secretDAL.invalidateSecretCacheByProjectId(projectId); await Promise.allSettled(folders.map((el) => (el?.id ? snapshotService.performSnapshot(el.id) : undefined))); await Promise.allSettled( folders.map((el) => @@ -2024,7 +2024,7 @@ export const secretV2BridgeServiceFactory = ({ }) ); - await secretDAL.cacheInvalidateSecretByProjectId(projectId); + await secretDAL.invalidateSecretCacheByProjectId(projectId); await snapshotService.performSnapshot(folderId); await secretQueueService.syncSecrets({ actor, @@ -2549,7 +2549,7 @@ export const secretV2BridgeServiceFactory = ({ }); if (isDestinationUpdated || isSourceUpdated) { - await secretDAL.cacheInvalidateSecretByProjectId(projectId); + await secretDAL.invalidateSecretCacheByProjectId(projectId); } if (isDestinationUpdated) { await snapshotService.performSnapshot(destinationFolder.id); @@ -2729,7 +2729,7 @@ export const secretV2BridgeServiceFactory = ({ generatePaths(folderMap).map(({ folderId, path }) => [folderId, path === "/" ? path : path.substring(1)]) ); - const secrets = await secretDAL.findByFolderIds({ folderIds: folders.map((f) => f.id), projectId }); + const secrets = await secretDAL.findByFolderIds({ folderIds: folders.map((f) => f.id), projectId, useCache: true }); const { decryptor: secretManagerDecryptor } = await kmsService.createCipherPairWithDataKey({ type: KmsDataKey.SecretManager,