From 2f927197710120e9c05b13ae7447a46c1a9d6cd6 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Thu, 16 May 2024 00:29:07 +0200 Subject: [PATCH 1/5] Fix: Secret expansion with recursive mode --- backend/src/services/secret/secret-fns.ts | 2 +- backend/src/services/secret/secret-service.ts | 31 +++++++++++++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/backend/src/services/secret/secret-fns.ts b/backend/src/services/secret/secret-fns.ts index 007f8cb9e..8bcfa3a42 100644 --- a/backend/src/services/secret/secret-fns.ts +++ b/backend/src/services/secret/secret-fns.ts @@ -353,7 +353,7 @@ export const interpolateSecrets = ({ projectId, secretEncKey, secretDAL, folderD }; export const decryptSecretRaw = ( - secret: TSecrets & { workspace: string; environment: string; secretPath?: string }, + secret: TSecrets & { workspace: string; environment: string; secretPath: string }, key: string ) => { const secretKey = decryptSymmetric128BitHexKeyUTF8({ diff --git a/backend/src/services/secret/secret-service.ts b/backend/src/services/secret/secret-service.ts index aa5867c4a..523fdb282 100644 --- a/backend/src/services/secret/secret-service.ts +++ b/backend/src/services/secret/secret-service.ts @@ -285,7 +285,7 @@ export const secretServiceFactory = ({ await snapshotService.performSnapshot(folderId); await secretQueueService.syncSecrets({ secretPath: path, projectId, environment }); // TODO(akhilmhdh-pg): licence check, posthog service and snapshot - return { ...secret[0], environment, workspace: projectId, tags }; + return { ...secret[0], environment, workspace: projectId, tags, secretPath: path }; }; const updateSecret = async ({ @@ -415,7 +415,7 @@ export const secretServiceFactory = ({ await snapshotService.performSnapshot(folderId); await secretQueueService.syncSecrets({ secretPath: path, projectId, environment }); // TODO(akhilmhdh-pg): licence check, posthog service and snapshot - return { ...updatedSecret[0], workspace: projectId, environment }; + return { ...updatedSecret[0], workspace: projectId, environment, secretPath: path }; }; const deleteSecret = async ({ @@ -484,7 +484,7 @@ export const secretServiceFactory = ({ await secretQueueService.syncSecrets({ secretPath: path, projectId, environment }); // TODO(akhilmhdh-pg): licence check, posthog service and snapshot - return { ...deletedSecret[0], _id: deletedSecret[0].id, workspace: projectId, environment }; + return { ...deletedSecret[0], _id: deletedSecret[0].id, workspace: projectId, environment, secretPath: path }; }; const getSecrets = async ({ @@ -681,7 +681,8 @@ export const secretServiceFactory = ({ return { ...importedSecrets[i].secrets[j], workspace: projectId, - environment: importedSecrets[i].environment + environment: importedSecrets[i].environment, + secretPath: importedSecrets[i].secretPath }; } } @@ -689,7 +690,7 @@ export const secretServiceFactory = ({ } if (!secret) throw new BadRequestError({ message: "Secret not found" }); - return { ...secret, workspace: projectId, environment }; + return { ...secret, workspace: projectId, environment, secretPath: path }; }; const createManySecret = async ({ @@ -984,6 +985,7 @@ export const secretServiceFactory = ({ secretKey: string; secretValue: string; secretComment?: string; + secretPath: string; }[] ) => { const secretRecord: Record< @@ -996,7 +998,8 @@ export const secretServiceFactory = ({ > = {}; secretBatch.forEach((decryptedSecret) => { - secretRecord[decryptedSecret.secretKey] = { + const uniqueKey = `${decryptedSecret.secretPath}/${decryptedSecret.secretKey}`; + secretRecord[uniqueKey] = { value: decryptedSecret.secretValue, comment: decryptedSecret.secretComment }; @@ -1005,8 +1008,9 @@ export const secretServiceFactory = ({ await expandSecrets(secretRecord); secretBatch.forEach((decryptedSecret, index) => { + const uniqueKey = `${decryptedSecret.secretPath}/${decryptedSecret.secretKey}`; // eslint-disable-next-line no-param-reassign - secretBatch[index].secretValue = secretRecord[decryptedSecret.secretKey].value; + secretBatch[index].secretValue = secretRecord[uniqueKey].value; }); }; @@ -1055,6 +1059,7 @@ export const secretServiceFactory = ({ includeImports, version }); + return decryptSecretRaw(secret, botKey); }; @@ -1227,7 +1232,9 @@ export const secretServiceFactory = ({ await snapshotService.performSnapshot(secrets[0].folderId); await secretQueueService.syncSecrets({ secretPath, projectId, environment }); - return secrets.map((secret) => decryptSecretRaw({ ...secret, workspace: projectId, environment }, botKey)); + return secrets.map((secret) => + decryptSecretRaw({ ...secret, workspace: projectId, environment, secretPath }, botKey) + ); }; const updateManySecretsRaw = async ({ @@ -1279,7 +1286,9 @@ export const secretServiceFactory = ({ await snapshotService.performSnapshot(secrets[0].folderId); await secretQueueService.syncSecrets({ secretPath, projectId, environment }); - return secrets.map((secret) => decryptSecretRaw({ ...secret, workspace: projectId, environment }, botKey)); + return secrets.map((secret) => + decryptSecretRaw({ ...secret, workspace: projectId, environment, secretPath }, botKey) + ); }; const deleteManySecretsRaw = async ({ @@ -1313,7 +1322,9 @@ export const secretServiceFactory = ({ await snapshotService.performSnapshot(secrets[0].folderId); await secretQueueService.syncSecrets({ secretPath, projectId, environment }); - return secrets.map((secret) => decryptSecretRaw({ ...secret, workspace: projectId, environment }, botKey)); + return secrets.map((secret) => + decryptSecretRaw({ ...secret, workspace: projectId, environment, secretPath }, botKey) + ); }; const getSecretVersions = async ({ From 74fe673724b74a66e062d8fbea04fec782339da5 Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Wed, 15 May 2024 20:12:45 -0400 Subject: [PATCH 2/5] patch project identity update --- backend/.eslintrc.js | 1 + .../identity-project-service.ts | 23 +++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js index b23cf05ae..1b8f84610 100644 --- a/backend/.eslintrc.js +++ b/backend/.eslintrc.js @@ -38,6 +38,7 @@ module.exports = { "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-unsafe-enum-comparison": "off", "no-void": "off", + "no-await-in-loop": "off", "consistent-return": "off", // my style "import/order": "off", // for simple-import-order "import/prefer-default-export": "off", // why diff --git a/backend/src/services/identity-project/identity-project-service.ts b/backend/src/services/identity-project/identity-project-service.ts index 18a1803ac..0cc47a894 100644 --- a/backend/src/services/identity-project/identity-project-service.ts +++ b/backend/src/services/identity-project/identity-project-service.ts @@ -82,6 +82,7 @@ export const identityProjectServiceFactory = ({ role, project.id ); + const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission); if (!hasPriviledge) throw new ForbiddenRequestError({ @@ -135,16 +136,18 @@ export const identityProjectServiceFactory = ({ message: `Identity with id ${identityId} doesn't exists in project with id ${projectId}` }); - const { permission: identityRolePermission } = await permissionService.getProjectPermission( - ActorType.IDENTITY, - projectIdentity.identityId, - projectIdentity.projectId, - actorAuthMethod, - actorOrgId - ); - const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, identityRolePermission); - if (!hasRequiredPriviledges) - throw new ForbiddenRequestError({ message: "Failed to delete more privileged identity" }); + for (const { role: requestedRoleChange } of roles) { + const { permission: rolePermission } = await permissionService.getProjectPermissionByRole( + requestedRoleChange, + projectId + ); + + const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, rolePermission); + + if (!hasRequiredPriviledges) { + throw new ForbiddenRequestError({ message: "Failed to change to a more privileged role" }); + } + } // validate custom roles input const customInputRoles = roles.filter( From 4a35623956e790d4869a8b2214c40809f8bc1dca Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Wed, 15 May 2024 20:19:10 -0400 Subject: [PATCH 3/5] remove for of with for await --- backend/.eslintrc.js | 1 - .../src/services/identity-project/identity-project-service.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js index 1b8f84610..b23cf05ae 100644 --- a/backend/.eslintrc.js +++ b/backend/.eslintrc.js @@ -38,7 +38,6 @@ module.exports = { "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-unsafe-enum-comparison": "off", "no-void": "off", - "no-await-in-loop": "off", "consistent-return": "off", // my style "import/order": "off", // for simple-import-order "import/prefer-default-export": "off", // why diff --git a/backend/src/services/identity-project/identity-project-service.ts b/backend/src/services/identity-project/identity-project-service.ts index 0cc47a894..13ecf8bbc 100644 --- a/backend/src/services/identity-project/identity-project-service.ts +++ b/backend/src/services/identity-project/identity-project-service.ts @@ -136,7 +136,7 @@ export const identityProjectServiceFactory = ({ message: `Identity with id ${identityId} doesn't exists in project with id ${projectId}` }); - for (const { role: requestedRoleChange } of roles) { + for await (const { role: requestedRoleChange } of roles) { const { permission: rolePermission } = await permissionService.getProjectPermissionByRole( requestedRoleChange, projectId From 75b8b521b3fc6a0d7cb9cdb85f595433cdb0c1a9 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Thu, 16 May 2024 03:31:01 +0200 Subject: [PATCH 4/5] Update secret-service.ts --- backend/src/services/secret/secret-service.ts | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/backend/src/services/secret/secret-service.ts b/backend/src/services/secret/secret-service.ts index 523fdb282..99bf480bf 100644 --- a/backend/src/services/secret/secret-service.ts +++ b/backend/src/services/secret/secret-service.ts @@ -981,37 +981,40 @@ export const secretServiceFactory = ({ }); const batchSecretsExpand = async ( - secretBatch: { - secretKey: string; - secretValue: string; - secretComment?: string; - secretPath: string; - }[] + secretBatch: { secretKey: string; secretValue: string; secretComment?: string; secretPath: string }[] ) => { - const secretRecord: Record< - string, - { - value: string; - comment?: string; - skipMultilineEncoding?: boolean; + // Group secrets by secretPath + const secretsByPath: Record = {}; + + secretBatch.forEach((secret) => { + if (!secretsByPath[secret.secretPath]) { + secretsByPath[secret.secretPath] = []; } - > = {}; - - secretBatch.forEach((decryptedSecret) => { - const uniqueKey = `${decryptedSecret.secretPath}/${decryptedSecret.secretKey}`; - secretRecord[uniqueKey] = { - value: decryptedSecret.secretValue, - comment: decryptedSecret.secretComment - }; + secretsByPath[secret.secretPath].push(secret); }); - await expandSecrets(secretRecord); + // Expand secrets for each group + for (const secPath in secretsByPath) { + if (!Object.hasOwn(secretsByPath, path)) { + // eslint-disable-next-line no-continue + continue; + } - secretBatch.forEach((decryptedSecret, index) => { - const uniqueKey = `${decryptedSecret.secretPath}/${decryptedSecret.secretKey}`; - // eslint-disable-next-line no-param-reassign - secretBatch[index].secretValue = secretRecord[uniqueKey].value; - }); + const secretRecord: Record = {}; + secretsByPath[secPath].forEach((decryptedSecret) => { + secretRecord[decryptedSecret.secretKey] = { + value: decryptedSecret.secretValue, + comment: decryptedSecret.secretComment + }; + }); + + await expandSecrets(secretRecord); + + secretsByPath[secPath].forEach((decryptedSecret) => { + // eslint-disable-next-line no-param-reassign + decryptedSecret.secretValue = secretRecord[decryptedSecret.secretKey].value; + }); + } }; // expand secrets From 4af703df5bfb975e8b392302bdf0e9cc03fc89d7 Mon Sep 17 00:00:00 2001 From: = Date: Thu, 16 May 2024 07:35:05 +0530 Subject: [PATCH 5/5] fix: resolved create secret failing for reference --- backend/src/services/secret/secret-fns.ts | 6 ++++-- backend/src/services/secret/secret-service.ts | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/backend/src/services/secret/secret-fns.ts b/backend/src/services/secret/secret-fns.ts index 8bcfa3a42..6b2b50920 100644 --- a/backend/src/services/secret/secret-fns.ts +++ b/backend/src/services/secret/secret-fns.ts @@ -520,7 +520,8 @@ export const fnSecretBulkInsert = async ({ inputSecrets.map(({ references = [], secretBlindIndex }) => ({ secretId: newSecretGroupByBlindIndex[secretBlindIndex as string][0].id, references - })) + })), + tx ); if (newSecretTags.length) { const secTags = await secretTagDAL.saveTagsToSecret(newSecretTags, tx); @@ -565,7 +566,8 @@ export const fnSecretBulkUpdate = async ({ .map(({ data: { references = [] } }, i) => ({ secretId: newSecrets[i].id, references - })) + })), + tx ); const secsUpdatedTag = inputSecrets.flatMap(({ data: { tags } }, i) => tags !== undefined ? { tags, secretId: newSecrets[i].id } : [] diff --git a/backend/src/services/secret/secret-service.ts b/backend/src/services/secret/secret-service.ts index 523fdb282..52b9d873b 100644 --- a/backend/src/services/secret/secret-service.ts +++ b/backend/src/services/secret/secret-service.ts @@ -1593,7 +1593,8 @@ export const secretServiceFactory = ({ key: botKey }) ) - })) + })), + tx ); });