diff --git a/backend/src/helpers/secrets.ts b/backend/src/helpers/secrets.ts index 818fdf85b..a693b88a3 100644 --- a/backend/src/helpers/secrets.ts +++ b/backend/src/helpers/secrets.ts @@ -991,11 +991,16 @@ const recursivelyExpandSecret = async ( expandedSec: Record, interpolatedSec: Record, fetchCrossEnv: (env: string, secPath: string[], secKey: string) => Promise, + recursionChainBreaker: Record, key: string ) => { if (expandedSec?.[key]) { return expandedSec[key]; } + if (recursionChainBreaker?.[key]) { + return ""; + } + recursionChainBreaker[key] = true; let interpolatedValue = interpolatedSec[key]; if (!interpolatedValue) { @@ -1013,12 +1018,13 @@ const recursivelyExpandSecret = async ( expandedSec, interpolatedSec, fetchCrossEnv, + recursionChainBreaker, interpolationKey ); if (val) { - interpolatedValue = interpolatedValue.replace(interpolationSyntax, val); + interpolatedValue = interpolatedValue.replaceAll(interpolationSyntax, val); } - return; + continue; } if (entities.length > 1) { @@ -1027,11 +1033,12 @@ const recursivelyExpandSecret = async ( const secRefKey = entities[entities.length - 1]; const val = await fetchCrossEnv(secRefEnv, secRefPath, secRefKey); - interpolatedValue = interpolatedValue.replace(interpolationSyntax, val); + interpolatedValue = interpolatedValue.replaceAll(interpolationSyntax, val); } } } + expandedSec[key] = interpolatedValue; return interpolatedValue; }; @@ -1057,17 +1064,21 @@ export const expandSecrets = async ( for (const key of Object.keys(secrets)) { if (expandedSec?.[key]) { secrets[key].value = expandedSec[key]; - return; + continue; } + // this is to avoid recursion loop. So the graph should be direct graph rather than cyclic + // so for any recursion building if there is an entity two times same key meaning it will be looped + const recursionChainBreaker: Record = {}; const expandedVal = await recursivelyExpandSecret( expandedSec, interpolatedSec, crossSecEnvFetch, + recursionChainBreaker, key ); - secrets[key].value = expandedVal || ""; + secrets[key].value = expandedVal; } return secrets; diff --git a/backend/src/integrations/sync.ts b/backend/src/integrations/sync.ts index e178af833..7ff8e71b4 100644 --- a/backend/src/integrations/sync.ts +++ b/backend/src/integrations/sync.ts @@ -59,9 +59,11 @@ import _ from "lodash"; import sodium from "libsodium-wrappers"; import { standardRequest } from "../config/request"; -const getSecretKeyValuePair = (secrets: Record) => +const getSecretKeyValuePair = ( + secrets: Record +) => Object.keys(secrets).reduce>((prev, key) => { - prev[key] = secrets[key].value; + if (secrets[key]) prev[key] = secrets[key]?.value || ""; return prev; }, {}); @@ -667,7 +669,7 @@ const syncSecretsHeroku = async ({ accessToken }: { integration: IIntegration; - secrets: Record; + secrets: Record; accessToken: string; }) => { const herokuSecrets = ( @@ -682,7 +684,7 @@ const syncSecretsHeroku = async ({ Object.keys(herokuSecrets).forEach((key) => { if (!(key in secrets)) { - delete secrets[key]; + secrets[key] = null; } }); diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 98ea0808a..d2f7a1b89 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -1,9 +1,7 @@ { "compilerOptions": { "target": "es2016", - "lib": [ - "es6" - ], + "lib": ["es6", "es2021"], "module": "commonjs", "rootDir": "src", "resolveJsonModule": true, @@ -15,15 +13,8 @@ "strict": true, "noImplicitAny": true, "skipLibCheck": true, - "typeRoots": [ - "./src/types", - "./node_modules/@types" - ] + "typeRoots": ["./src/types", "./node_modules/@types"] }, - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules" - ] -} \ No newline at end of file + "include": ["src/**/*"], + "exclude": ["node_modules"] +}