From d6ffd4fa5fc35163fa05681e4e5294e2a7685a4c Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Wed, 23 Oct 2024 17:23:17 +0400 Subject: [PATCH] fix: block precedence & root env priority --- .../external-migration-fns.ts | 152 +++++++++++++++++- .../external-migration-types.ts | 9 +- 2 files changed, 154 insertions(+), 7 deletions(-) diff --git a/backend/src/services/external-migration/external-migration-fns.ts b/backend/src/services/external-migration/external-migration-fns.ts index 90991c33a..c86482168 100644 --- a/backend/src/services/external-migration/external-migration-fns.ts +++ b/backend/src/services/external-migration/external-migration-fns.ts @@ -131,9 +131,9 @@ export const parseEnvKeyDataFn = async (decryptedJson: string): Promise ab.blockId === block.id).map((ab) => ab.appId); + const appsUsingBlock = parsedJson.appBlocks.filter((ab) => ab.blockId === block.id); - for (const appId of appsUsingBlock) { + for (const { appId, orderIndex } of appsUsingBlock) { // 2. Find the matching environment in the app based on the environment role const blockBaseEnv = parsedJson.baseEnvironments.find((be) => be.id === subEnv.parentEnvironmentId); @@ -160,20 +160,71 @@ export const parseEnvKeyDataFn = async (decryptedJson: string): Promise s.name === secretName && s.environmentId === matchingAppEnv.id + ); + + if (preExistingSecretIndex !== -1) { + const preExistingSecret = infisicalImportData.secrets[preExistingSecretIndex]; + + if ( + preExistingSecret.appBlockOrderIndex !== undefined && + orderIndex > preExistingSecret.appBlockOrderIndex + ) { + // if the existing secret has a lower orderIndex, we should replace it + infisicalImportData.secrets[preExistingSecretIndex] = { + ...preExistingSecret, + value: resolvedSecret.val || "", + appBlockOrderIndex: orderIndex + }; + } + + // eslint-disable-next-line no-continue + continue; + } + infisicalImportData.secrets.push({ id: randomUUID(), name: secretName, environmentId: matchingAppEnv.id, value: resolvedSecret.val || "", - folderId: `${subEnv.id}-${appId}` + folderId: `${subEnv.id}-${appId}`, + appBlockOrderIndex: orderIndex }); } else { + // If the secret already exists in the environment, we need to check the orderIndex of the appBlock. The appBlock with the highest orderIndex should take precedence. + const preExistingSecretIndex = infisicalImportData.secrets.findIndex( + (s) => s.name === secretName && s.environmentId === matchingAppEnv.id + ); + + if (preExistingSecretIndex !== -1) { + const preExistingSecret = infisicalImportData.secrets[preExistingSecretIndex]; + + if ( + preExistingSecret.appBlockOrderIndex !== undefined && + orderIndex > preExistingSecret.appBlockOrderIndex + ) { + // if the existing secret has a lower orderIndex, we should replace it + infisicalImportData.secrets[preExistingSecretIndex] = { + ...preExistingSecret, + value: secretData.val || "", + appBlockOrderIndex: orderIndex + }; + } + + // eslint-disable-next-line no-continue + continue; + } + infisicalImportData.secrets.push({ id: randomUUID(), name: secretName, environmentId: matchingAppEnv.id, value: secretData.val || "", - folderId: `${subEnv.id}-${appId}` + folderId: `${subEnv.id}-${appId}`, + appBlockOrderIndex: orderIndex }); } } @@ -229,18 +280,69 @@ export const parseEnvKeyDataFn = async (decryptedJson: string): Promise s.name === secret && s.environmentId === matchingEnv.id + ); + + if (preExistingSecretIndex !== -1) { + const preExistingSecret = infisicalImportData.secrets[preExistingSecretIndex]; + + if ( + preExistingSecret.appBlockOrderIndex !== undefined && + appBlock.orderIndex > preExistingSecret.appBlockOrderIndex + ) { + // if the existing secret has a lower orderIndex, we should replace it + infisicalImportData.secrets[preExistingSecretIndex] = { + ...preExistingSecret, + value: selectedSecret.val || "", + appBlockOrderIndex: appBlock.orderIndex + }; + } + + // eslint-disable-next-line no-continue + continue; + } + infisicalImportData.secrets.push({ id: randomUUID(), name: secret, environmentId: matchingEnv.id, - value: resolvedSecret.val || "" + value: resolvedSecret.val || "", + appBlockOrderIndex: appBlock.orderIndex }); } else { + // If the secret already exists in the environment, we need to check the orderIndex of the appBlock. The appBlock with the highest orderIndex should take precedence. + const preExistingSecretIndex = infisicalImportData.secrets.findIndex( + (s) => s.name === secret && s.environmentId === matchingEnv.id + ); + + if (preExistingSecretIndex !== -1) { + const preExistingSecret = infisicalImportData.secrets[preExistingSecretIndex]; + + if ( + preExistingSecret.appBlockOrderIndex !== undefined && + appBlock.orderIndex > preExistingSecret.appBlockOrderIndex + ) { + // if the existing secret has a lower orderIndex, we should replace it + infisicalImportData.secrets[preExistingSecretIndex] = { + ...preExistingSecret, + value: selectedSecret.val || "", + appBlockOrderIndex: appBlock.orderIndex + }; + } + + // eslint-disable-next-line no-continue + continue; + } + infisicalImportData.secrets.push({ id: randomUUID(), name: secret, environmentId: matchingEnv.id, - value: selectedSecret.val || "" + value: selectedSecret.val || "", + appBlockOrderIndex: appBlock.orderIndex }); } } @@ -291,8 +393,30 @@ export const parseEnvKeyDataFn = async (decryptedJson: string): Promise s.name === secretName && s.environmentId === environmentId + ); + if (secretData.inheritsEnvironmentId) { const resolvedSecret = findRootInheritedSecret(secretData, secretName, parsedJson.envs); + + // Check if there's already a secret with this name in the environment, if there is, we should override it. Because if there's already one, we know its coming from a block. + // Variables from the normal environment should take precedence over variables from the block. + + if (indexOfExistingSecret !== -1) { + // if a existing secret is found, we should replace it directly + const newSecret: (typeof infisicalImportData.secrets)[number] = { + ...infisicalImportData.secrets[indexOfExistingSecret], + value: resolvedSecret.val || "" + }; + + infisicalImportData.secrets[indexOfExistingSecret] = newSecret; + + // eslint-disable-next-line no-continue + continue; + } + infisicalImportData.secrets.push({ id: randomUUID(), name: secretName, @@ -301,6 +425,22 @@ export const parseEnvKeyDataFn = async (decryptedJson: string): Promise; environments: Array<{ name: string; id: string; projectId: string; envParentId?: string }>; folders: Array<{ id: string; name: string; environmentId: string; parentFolderId?: string }>; - secrets: Array<{ id: string; name: string; environmentId: string; value: string; folderId?: string }>; + secrets: Array<{ + id: string; + name: string; + environmentId: string; + value: string; + folderId?: string; + appBlockOrderIndex?: number; // Not used for infisical import, only used for building the import structure to determine which block(s) take precedence. + }>; }; export type TImportEnvKeyDataCreate = {