diff --git a/backend/src/lib/fn/array.ts b/backend/src/lib/fn/array.ts index 1e075101b..00819ceb8 100644 --- a/backend/src/lib/fn/array.ts +++ b/backend/src/lib/fn/array.ts @@ -17,6 +17,23 @@ export const groupBy = ( {} as Record ); +/** + * Sorts an array of items into groups. The return value is a map where the keys are + * the group ids the given getGroupId function produced and the value will be the last found one for the group key + */ +export const groupByUnique = ( + array: readonly T[], + getGroupId: (item: T) => Key +): Record => + array.reduce( + (acc, item) => { + const groupId = getGroupId(item); + acc[groupId] = item; + return acc; + }, + {} as Record + ); + /** * Given a list of items returns a new list with only * unique items. Accepts an optional identity function diff --git a/backend/src/services/secret-import/secret-import-fns.ts b/backend/src/services/secret-import/secret-import-fns.ts index eb6a94bf5..1ccaaefc2 100644 --- a/backend/src/services/secret-import/secret-import-fns.ts +++ b/backend/src/services/secret-import/secret-import-fns.ts @@ -1,5 +1,5 @@ import { SecretType, TSecretImports, TSecrets, TSecretsV2 } from "@app/db/schemas"; -import { groupBy } from "@app/lib/fn"; +import { groupBy, unique } from "@app/lib/fn"; import { TSecretDALFactory } from "../secret/secret-dal"; import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal"; @@ -146,7 +146,8 @@ export const fnSecretsV2FromImports = async ({ secretImportDAL, depth = 0, cyclicDetector = new Set(), - decryptor + decryptor, + expandSecretReferences }: { allowedImports: (Omit & { importEnv: { id: string; slug: string; name: string }; @@ -157,6 +158,9 @@ export const fnSecretsV2FromImports = async ({ depth?: number; cyclicDetector?: Set; decryptor: (value?: Buffer | null) => string | undefined; + expandSecretReferences?: ( + secrets: Record + ) => Promise>; }) => { // avoid going more than a depth if (depth >= LEVEL_BREAK) return []; @@ -206,16 +210,27 @@ export const fnSecretsV2FromImports = async ({ secretDAL, depth: depth + 1, cyclicDetector, - decryptor + decryptor, + expandSecretReferences }); } const secretsFromdeeperImportGroupedByFolderId = groupBy(secretsFromDeeperImports, (i) => i.importFolderId); - const secrets = allowedImports.map(({ importPath, importEnv, id, folderId }, i) => { + const processedImports = allowedImports.map(({ importPath, importEnv, id, folderId }, i) => { const sourceImportFolder = importedFolderGroupBySourceImport[`${importEnv.id}-${importPath}`][0]; const folderDeeperImportSecrets = secretsFromdeeperImportGroupedByFolderId?.[sourceImportFolder?.id || ""]?.[0]?.secrets || []; - + const secretsWithDuplicate = (importedSecretsGroupByFolderId?.[importedFolders?.[i]?.id as string] || []) + .map((item) => ({ + ...item, + secretKey: item.key, + secretValue: decryptor(item.encryptedValue), + secretComment: decryptor(item.encryptedComment), + environment: importEnv.slug, + workspace: "", // This field should not be used, it's only here to keep the older Python SDK versions backwards compatible with the new Postgres backend. + _id: item.id // The old Python SDK depends on the _id field being returned. We return this to keep the older Python SDK versions backwards compatible with the new Postgres backend. + })) + .concat(folderDeeperImportSecrets); return { secretPath: importPath, environment: importEnv.slug, @@ -223,19 +238,33 @@ export const fnSecretsV2FromImports = async ({ folderId: importedFolders?.[i]?.id, id, importFolderId: folderId, - secrets: (importedSecretsGroupByFolderId?.[importedFolders?.[i]?.id as string] || []) - .map((item) => ({ - ...item, - secretKey: item.key, - secretValue: decryptor(item.encryptedValue), - secretComment: decryptor(item.encryptedComment), - environment: importEnv.slug, - workspace: "", // This field should not be used, it's only here to keep the older Python SDK versions backwards compatible with the new Postgres backend. - _id: item.id // The old Python SDK depends on the _id field being returned. We return this to keep the older Python SDK versions backwards compatible with the new Postgres backend. - })) - .concat(folderDeeperImportSecrets) + secrets: unique(secretsWithDuplicate, (el) => el.secretKey) }; }); - return secrets; + if (expandSecretReferences) { + await Promise.all( + processedImports.map(async (processedImport) => { + const secretsGroupByKey = processedImport.secrets.reduce( + (acc, item) => { + acc[item.secretKey] = { + value: item.secretValue, + comment: item.secretComment, + skipMultilineEncoding: item.skipMultilineEncoding + }; + return acc; + }, + {} as Record + ); + // eslint-disable-next-line + await expandSecretReferences(secretsGroupByKey); + processedImport.secrets.forEach((decryptedSecret) => { + // eslint-disable-next-line no-param-reassign + decryptedSecret.secretValue = secretsGroupByKey[decryptedSecret.secretKey].value; + }); + }) + ); + } + + return processedImports; }; diff --git a/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts b/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts index 76553902d..19aef06f3 100644 --- a/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts +++ b/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts @@ -363,49 +363,60 @@ export const recursivelyGetSecretPaths = async ({ return allowedPaths; }; +// used to convert multi line ones to quotes ones with \n +const formatMultiValueEnv = (val?: string) => { + if (!val) return ""; + if (!val.match("\n")) return val; + return `"${val.replace(/\n/g, "\\n")}"`; +}; type TInterpolateSecretArg = { projectId: string; - decryptSecret: (encryptedValue?: Buffer | null) => string | undefined; + decryptSecretValue: (encryptedValue?: Buffer | null) => string | undefined; secretDAL: Pick; folderDAL: Pick; }; -export const interpolateSecrets = ({ projectId, decryptSecret, secretDAL, folderDAL }: TInterpolateSecretArg) => { - const fetchSecretsCrossEnv = () => { - const fetchCache: Record> = {}; +export const expandSecretReferencesFactory = ({ + projectId, + decryptSecretValue: decryptSecret, + secretDAL, + folderDAL +}: TInterpolateSecretArg) => { + const fetchSecretFactory = () => { + const secretCache: Record> = {}; return async (secRefEnv: string, secRefPath: string[], secRefKey: string) => { - const secRefPathUrl = path.join("/", ...secRefPath); - const uniqKey = `${secRefEnv}-${secRefPathUrl}`; + const referredSecretPathURL = path.join("/", ...secRefPath); + const uniqueKey = `${secRefEnv}-${referredSecretPathURL}`; - if (fetchCache?.[uniqKey]) { - return fetchCache[uniqKey][secRefKey]; + if (secretCache?.[uniqueKey]) { + return secretCache[uniqueKey][secRefKey]; } - const folder = await folderDAL.findBySecretPath(projectId, secRefEnv, secRefPathUrl); + const folder = await folderDAL.findBySecretPath(projectId, secRefEnv, referredSecretPathURL); if (!folder) return ""; const secrets = await secretDAL.findByFolderId(folder.id); - const decryptedSec = secrets.reduce>((prev, secret) => { + const decryptedSecret = secrets.reduce>((prev, secret) => { // eslint-disable-next-line prev[secret.key] = decryptSecret(secret.encryptedValue) || ""; return prev; }, {}); - fetchCache[uniqKey] = decryptedSec; + secretCache[uniqueKey] = decryptedSecret; - return fetchCache[uniqKey][secRefKey]; + return secretCache[uniqueKey][secRefKey]; }; }; const recursivelyExpandSecret = async ( - expandedSec: Record, - interpolatedSec: Record, - fetchCrossEnv: (env: string, secPath: string[], secKey: string) => Promise, + expandedSec: Record, + interpolatedSec: Record, + fetchSecret: (env: string, secPath: string[], secKey: string) => Promise, recursionChainBreaker: Record, key: string - ) => { + ): Promise => { if (expandedSec?.[key] !== undefined) { return expandedSec[key]; } @@ -433,7 +444,7 @@ export const interpolateSecrets = ({ projectId, decryptSecret, secretDAL, folder const val = await recursivelyExpandSecret( expandedSec, interpolatedSec, - fetchCrossEnv, + fetchSecret, recursionChainBreaker, interpolationKey ); @@ -450,7 +461,7 @@ export const interpolateSecrets = ({ projectId, decryptSecret, secretDAL, folder const secRefKey = entities[entities.length - 1]; // eslint-disable-next-line - const val = await fetchCrossEnv(secRefEnv, secRefPath, secRefKey); + const val = await fetchSecret(secRefEnv, secRefPath, secRefKey); if (val) { interpolatedValue = interpolatedValue.replaceAll(interpolationSyntax, val); } @@ -463,36 +474,28 @@ export const interpolateSecrets = ({ projectId, decryptSecret, secretDAL, folder return interpolatedValue; }; - // used to convert multi line ones to quotes ones with \n - const formatMultiValueEnv = (val?: string) => { - if (!val) return ""; - if (!val.match("\n")) return val; - return `"${val.replace(/\n/g, "\\n")}"`; - }; - + const fetchSecret = fetchSecretFactory(); const expandSecrets = async ( - secrets: Record + inputSecrets: Record ) => { - const expandedSec: Record = {}; - const interpolatedSec: Record = {}; + const expandedSecrets: Record = {}; + const toBeExpandedSecrets: Record = {}; - const crossSecEnvFetch = fetchSecretsCrossEnv(); - - Object.keys(secrets).forEach((key) => { - if (secrets[key].value.match(INTERPOLATION_SYNTAX_REG)) { - interpolatedSec[key] = secrets[key].value; + Object.keys(inputSecrets).forEach((key) => { + if (inputSecrets[key].value?.match(INTERPOLATION_SYNTAX_REG)) { + toBeExpandedSecrets[key] = inputSecrets[key].value; } else { - expandedSec[key] = secrets[key].value; + expandedSecrets[key] = inputSecrets[key].value; } }); - for (const key of Object.keys(secrets)) { - if (expandedSec?.[key]) { + for (const key of Object.keys(inputSecrets)) { + if (expandedSecrets?.[key]) { // should not do multi line encoding if user has set it to skip // eslint-disable-next-line - secrets[key].value = secrets[key].skipMultilineEncoding - ? formatMultiValueEnv(expandedSec[key]) - : expandedSec[key]; + inputSecrets[key].value = inputSecrets[key].skipMultilineEncoding + ? formatMultiValueEnv(expandedSecrets[key]) + : expandedSecrets[key]; // eslint-disable-next-line continue; } @@ -502,18 +505,20 @@ export const interpolateSecrets = ({ projectId, decryptSecret, secretDAL, folder const recursionChainBreaker: Record = {}; // eslint-disable-next-line const expandedVal = await recursivelyExpandSecret( - expandedSec, - interpolatedSec, - crossSecEnvFetch, + expandedSecrets, + toBeExpandedSecrets, + fetchSecret, recursionChainBreaker, key ); // eslint-disable-next-line - secrets[key].value = secrets[key].skipMultilineEncoding ? formatMultiValueEnv(expandedVal) : expandedVal; + inputSecrets[key].value = inputSecrets[key].skipMultilineEncoding + ? formatMultiValueEnv(expandedVal) + : expandedVal; } - return secrets; + return inputSecrets; }; return expandSecrets; }; 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 31856c42c..34e568ca7 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 @@ -24,11 +24,11 @@ import { fnSecretsV2FromImports } from "../secret-import/secret-import-fns"; import { TSecretTagDALFactory } from "../secret-tag/secret-tag-dal"; import { TSecretV2BridgeDALFactory } from "./secret-v2-bridge-dal"; import { + expandSecretReferencesFactory, fnSecretBulkDelete, fnSecretBulkInsert, fnSecretBulkUpdate, getAllNestedSecretReferences, - interpolateSecrets, recursivelyGetSecretPaths, reshapeBridgeSecret } from "./secret-v2-bridge-fns"; @@ -428,7 +428,8 @@ export const secretV2BridgeServiceFactory = ({ actorOrgId, actorAuthMethod, includeImports, - recursive // TODO(akhilmhdh-sev2): add logic for expandSecretReferences + recursive, + expandSecretReferences: shouldExpandSecretReferences }: TGetSecretsDTO) => { const { permission } = await permissionService.getProjectPermission( actor, @@ -484,57 +485,81 @@ export const secretV2BridgeServiceFactory = ({ projectId }); - if (includeImports) { - const secretImports = await secretImportDAL.findByFolderIds(paths.map((p) => p.folderId)); - const allowedImports = secretImports.filter(({ importEnv, importPath, isReplication }) => - !isReplication && - // if its service token allow full access over imported one - actor === ActorType.SERVICE - ? true - : permission.can( - ProjectPermissionActions.Read, - subject(ProjectPermissionSub.Secrets, { - environment: importEnv.slug, - secretPath: importPath - }) - ) - ); - const importedSecrets = await fnSecretsV2FromImports({ - allowedImports, - secretDAL, - folderDAL, - secretImportDAL, - decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined) - }); + const decryptedSecrets = secrets.map((secret) => + reshapeBridgeSecret(projectId, environment, groupedPaths[secret.folderId][0].path, { + ...secret, + value: secret.encryptedValue + ? secretManagerDecryptor({ cipherTextBlob: secret.encryptedValue }).toString() + : undefined, + comment: secret.encryptedComment + ? secretManagerDecryptor({ cipherTextBlob: secret.encryptedComment }).toString() + : undefined + }) + ); + const expandSecretReferences = expandSecretReferencesFactory({ + projectId, + folderDAL, + secretDAL, + decryptSecretValue: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined) + }); + if (shouldExpandSecretReferences) { + const secretsGroupByPath = groupBy(decryptedSecrets, (i) => i.secretPath); + for (const secretPathKey in secretsGroupByPath) { + if (Object.hasOwn(secretsGroupByPath, secretPathKey)) { + const secretsGroupByKey = secretsGroupByPath[secretPathKey].reduce( + (acc, item) => { + acc[item.secretKey] = { + value: item.secretValue, + comment: item.secretComment, + skipMultilineEncoding: item.skipMultilineEncoding + }; + return acc; + }, + {} as Record + ); + // eslint-disable-next-line + await expandSecretReferences(secretsGroupByKey); + secretsGroupByPath[secretPathKey].forEach((decryptedSecret) => { + // eslint-disable-next-line no-param-reassign + decryptedSecret.secretValue = secretsGroupByKey[decryptedSecret.secretKey].value; + }); + } + } + } + + if (!includeImports) { return { - secrets: secrets.map((secret) => - reshapeBridgeSecret(projectId, environment, groupedPaths[secret.folderId][0].path, { - ...secret, - value: secret.encryptedValue - ? secretManagerDecryptor({ cipherTextBlob: secret.encryptedValue }).toString() - : undefined, - comment: secret.encryptedComment - ? secretManagerDecryptor({ cipherTextBlob: secret.encryptedComment }).toString() - : undefined - }) - ), - imports: importedSecrets + secrets: decryptedSecrets }; } + const secretImports = await secretImportDAL.findByFolderIds(paths.map((p) => p.folderId)); + const allowedImports = secretImports.filter(({ importEnv, importPath, isReplication }) => + !isReplication && + // if its service token allow full access over imported one + actor === ActorType.SERVICE + ? true + : permission.can( + ProjectPermissionActions.Read, + subject(ProjectPermissionSub.Secrets, { + environment: importEnv.slug, + secretPath: importPath + }) + ) + ); + const importedSecrets = await fnSecretsV2FromImports({ + allowedImports, + secretDAL, + folderDAL, + secretImportDAL, + expandSecretReferences, + decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined) + }); + return { - secrets: secrets.map((secret) => - reshapeBridgeSecret(projectId, environment, groupedPaths[secret.folderId][0].path, { - ...secret, - value: secret.encryptedValue - ? secretManagerDecryptor({ cipherTextBlob: secret.encryptedValue }).toString() - : undefined, - comment: secret.encryptedComment - ? secretManagerDecryptor({ cipherTextBlob: secret.encryptedComment }).toString() - : undefined - }) - ) + secrets: decryptedSecrets, + imports: importedSecrets }; }; @@ -550,7 +575,7 @@ export const secretV2BridgeServiceFactory = ({ secretName, version, includeImports, - expandSecretReferences + expandSecretReferences: shouldExpandSecretReferences }: TGetASecretDTO) => { const { permission } = await permissionService.getProjectPermission( actor, @@ -600,11 +625,11 @@ export const secretV2BridgeServiceFactory = ({ }) .then((el) => SecretsV2Schema.parse({ ...el, id: el.secretId }))); - const interpolateInlineSecretReference = interpolateSecrets({ + const expandSecretReferences = expandSecretReferencesFactory({ projectId, - decryptSecret: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined), + folderDAL, secretDAL, - folderDAL + decryptSecretValue: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined) }); // now if secret is not found @@ -629,33 +654,20 @@ export const secretV2BridgeServiceFactory = ({ secretDAL, folderDAL, secretImportDAL, - decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined) + decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : undefined), + expandSecretReferences: shouldExpandSecretReferences ? expandSecretReferences : undefined }); for (let i = importedSecrets.length - 1; i >= 0; i -= 1) { for (let j = 0; j < importedSecrets[i].secrets.length; j += 1) { - if (secretName === importedSecrets[i].secrets[j].key) { - const importedSecret = importedSecrets[i].secrets[j]; - let secretValue = importedSecret.encryptedValue - ? secretManagerDecryptor({ cipherTextBlob: importedSecret.encryptedValue }).toString() - : undefined; - - if (expandSecretReferences && secretValue) { - const secretReferenceExpandedString = { - [importedSecret.key]: { value: secretValue } - }; - // eslint-disable-next-line - await interpolateInlineSecretReference(secretReferenceExpandedString); - secretValue = secretReferenceExpandedString[importedSecret.key].value; - } - - return reshapeBridgeSecret(projectId, importedSecrets[i].environment, importedSecrets[i].secretPath, { - ...importedSecret, - value: secretValue, - comment: importedSecret.encryptedComment - ? secretManagerDecryptor({ cipherTextBlob: importedSecret.encryptedComment }).toString() - : undefined - }); + const importedSecret = importedSecrets[i].secrets[j]; + if (secretName === importedSecret.key) { + return reshapeBridgeSecret( + projectId, + importedSecrets[i].environment, + importedSecrets[i].secretPath, + importedSecret + ); } } } @@ -665,13 +677,13 @@ export const secretV2BridgeServiceFactory = ({ let secretValue = secret.encryptedValue ? secretManagerDecryptor({ cipherTextBlob: secret.encryptedValue }).toString() : undefined; - if (expandSecretReferences && secretValue) { - const secretReferenceExpandedString = { + if (shouldExpandSecretReferences && secretValue) { + const secretReferenceExpandedRecord = { [secret.key]: { value: secretValue } }; // eslint-disable-next-line - await interpolateInlineSecretReference(secretReferenceExpandedString); - secretValue = secretReferenceExpandedString[secret.key].value; + await expandSecretReferences(secretReferenceExpandedRecord); + secretValue = secretReferenceExpandedRecord[secret.key].value; } return reshapeBridgeSecret(projectId, environment, path, { diff --git a/backend/src/services/secret/secret-queue.ts b/backend/src/services/secret/secret-queue.ts index 49cd227cf..ca9d73386 100644 --- a/backend/src/services/secret/secret-queue.ts +++ b/backend/src/services/secret/secret-queue.ts @@ -30,8 +30,9 @@ import { TProjectEnvDALFactory } from "../project-env/project-env-dal"; import { TProjectMembershipDALFactory } from "../project-membership/project-membership-dal"; import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal"; import { TSecretImportDALFactory } from "../secret-import/secret-import-dal"; +import { fnSecretsV2FromImports } from "../secret-import/secret-import-fns"; import { TSecretV2BridgeDALFactory } from "../secret-v2-bridge/secret-v2-bridge-dal"; -import { getAllNestedSecretReferences } from "../secret-v2-bridge/secret-v2-bridge-fns"; +import { expandSecretReferencesFactory, getAllNestedSecretReferences } from "../secret-v2-bridge/secret-v2-bridge-fns"; import { TSecretVersionV2DALFactory } from "../secret-v2-bridge/secret-version-dal"; import { TSecretVersionV2TagDALFactory } from "../secret-v2-bridge/secret-version-tag-dal"; import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service"; @@ -55,7 +56,7 @@ type TSecretQueueFactoryDep = { integrationAuthService: Pick; folderDAL: TSecretFolderDALFactory; secretDAL: TSecretDALFactory; - secretImportDAL: Pick; + secretImportDAL: Pick; webhookDAL: Pick; projectEnvDAL: Pick; projectDAL: TProjectDALFactory; @@ -249,7 +250,7 @@ export const secretQueueFactory = ({ depth: number; decryptor: (value: Buffer | null | undefined) => string; }) => { - let content: TIntegrationSecret = {}; + const content: TIntegrationSecret = {}; if (dto.depth > MAX_SYNC_SECRET_DEPTH) { logger.info( `getIntegrationSecrets: secret depth exceeded for [projectId=${dto.projectId}] [folderId=${dto.folderId}] [depth=${dto.depth}]` @@ -272,38 +273,40 @@ export const secretQueueFactory = ({ content[secretKey].skipMultilineEncoding = Boolean(secret.skipMultilineEncoding); }); - // TODO(akhilmhdh-sev2): change this to v2 expand secrets + const expandSecretReferences = expandSecretReferencesFactory({ + decryptSecretValue: dto.decryptor, + secretDAL: secretV2BridgeDAL, + folderDAL, + projectId: dto.projectId + }); + await expandSecretReferences(content); // check if current folder has any imports from other folders - const secretImport = await secretImportDAL.find({ folderId: dto.folderId, isReplication: false }); + const secretImports = await secretImportDAL.find({ folderId: dto.folderId, isReplication: false }); // if no imports then return secrets in the current folder - if (!secretImport) return content; + if (!secretImports.length) return content; + const importedSecrets = await fnSecretsV2FromImports({ + decryptor: dto.decryptor, + folderDAL, + secretDAL: secretV2BridgeDAL, + expandSecretReferences, + secretImportDAL, + allowedImports: secretImports + }); - const importedFolders = await folderDAL.findByManySecretPath( - secretImport.map(({ importEnv, importPath }) => ({ - envId: importEnv.id, - secretPath: importPath - })) - ); - - for await (const folder of importedFolders) { - if (folder) { - // get secrets contained in each imported folder by recursively calling - // this function against the imported folder - const importedSecrets = await getIntegrationSecretsV2({ - environment: dto.environment, - projectId: dto.projectId, - folderId: folder.id, - depth: dto.depth + 1, - decryptor: dto.decryptor - }); - - // add the imported secrets to the current folder secrets - content = { ...importedSecrets, ...content }; + for (let i = importedSecrets.length - 1; i >= 0; i -= 1) { + for (let j = 0; j < importedSecrets[i].secrets.length; j += 1) { + const importedSecret = importedSecrets[i].secrets[j]; + if (!content[importedSecret.key]) { + content[importedSecret.key] = { + skipMultilineEncoding: importedSecret.skipMultilineEncoding, + comment: importedSecret.secretComment, + value: importedSecret.secretValue || "" + }; + } } } - return content; }; @@ -628,6 +631,23 @@ export const secretQueueFactory = ({ logger.info( `getIntegrationSecrets: secret integration sync started [jobId=${job.id}] [jobId=${job.id}] [projectId=${job.data.projectId}] [environment=${job.data.environment}] [secretPath=${job.data.secretPath}] [depth=${job.data.depth}]` ); + + const secrets = shouldUseSecretV2Bridge + ? await getIntegrationSecretsV2({ + environment, + projectId, + folderId: folder.id, + depth: 1, + decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : "") + }) + : await getIntegrationSecrets({ + environment, + projectId, + folderId: folder.id, + key: botKey as string, + depth: 1 + }); + for (const integration of toBeSyncedIntegrations) { const integrationAuth = { ...integration.integrationAuth, @@ -661,21 +681,6 @@ export const secretQueueFactory = ({ }); } - const secrets = shouldUseSecretV2Bridge - ? await getIntegrationSecretsV2({ - environment, - projectId, - folderId: folder.id, - depth: 1, - decryptor: (value) => (value ? secretManagerDecryptor({ cipherTextBlob: value }).toString() : "") - }) - : await getIntegrationSecrets({ - environment, - projectId, - folderId: folder.id, - key: botKey as string, - depth: 1 - }); const suffixedSecrets: typeof secrets = {}; const metadata = integration.metadata as Record; if (metadata) {