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 c9cbf3b15..67a477141 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 @@ -484,13 +484,14 @@ export const secretApprovalRequestServiceFactory = ({ }); await snapshotService.performSnapshot(folderId); const [folder] = await folderDAL.findSecretPathByFolderIds(projectId, [folderId]); - // TODO(akhilmhdh-pg): change query to do secret path from folder + if (!folder) throw new BadRequestError({ message: "Folder not found" }); await secretQueueService.syncSecrets({ projectId, secretPath: folder.path, environmentSlug: folder.environmentSlug, folderId: folder.id, - membershipId: membership.id, + actorId, + actor, environmentId: folder.envId, secrets: mergeStatus.secrets.created .map(({ id, version }) => ({ diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index c018cfc26..34eb5fa28 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -679,7 +679,8 @@ export const registerRoutes = async ( secretApprovalRequestDAL, secretApprovalRequestSecretDAL, secretQueueService, - snapshotService + snapshotService, + projectMembershipDAL }); const secretRotationQueue = secretRotationQueueFactory({ telemetryService, diff --git a/backend/src/services/secret-import/secret-import-service.ts b/backend/src/services/secret-import/secret-import-service.ts index 0ff82370a..2e9c682a2 100644 --- a/backend/src/services/secret-import/secret-import-service.ts +++ b/backend/src/services/secret-import/secret-import-service.ts @@ -56,7 +56,7 @@ export const secretImportServiceFactory = ({ isReplication, path }: TCreateSecretImportDTO) => { - const { permission, membership } = await permissionService.getProjectPermission( + const { permission } = await permissionService.getProjectPermission( actor, actorId, projectId, @@ -111,7 +111,7 @@ export const secretImportServiceFactory = ({ ); }); - if (secImport.isReplication && sourceFolder && membership) { + if (secImport.isReplication && sourceFolder) { const importedSecrets = await secretDAL.find({ folderId: sourceFolder?.id }); await secretQueueService.replicateSecrets({ secretPath: secImport.importPath, @@ -120,8 +120,8 @@ export const secretImportServiceFactory = ({ pickOnlyImportIds: [secImport.id], folderId: sourceFolder.id, secrets: importedSecrets.map(({ id, version }) => ({ operation: SecretOperations.Create, version, id })), - // TODO(akhilmhdh): approval based replication this will fail for identity - membershipId: membership.id, + actorId, + actor, environmentId: importEnv.id }); } else { @@ -310,8 +310,8 @@ export const secretImportServiceFactory = ({ pickOnlyImportIds: [secretImportDoc.id], folderId: sourceFolder.id, secrets: importedSecrets.map(({ id, version }) => ({ operation: SecretOperations.Create, version, id })), - // TODO(akhilmhdh): approval based replication this will fail for identity - membershipId: membership.id, + actorId, + actor, environmentId: secretImportDoc.importEnv.id }); } diff --git a/backend/src/services/secret-replication/secret-replication-service.ts b/backend/src/services/secret-replication/secret-replication-service.ts index 1b1aed5a9..f5a585930 100644 --- a/backend/src/services/secret-replication/secret-replication-service.ts +++ b/backend/src/services/secret-replication/secret-replication-service.ts @@ -9,6 +9,8 @@ import { logger } from "@app/lib/logger"; import { alphaNumericNanoId } from "@app/lib/nanoid"; import { QueueJobs, QueueName, TQueueServiceFactory } from "@app/queue"; +import { ActorType } from "../auth/auth-type"; +import { TProjectMembershipDALFactory } from "../project-membership/project-membership-dal"; import { TSecretDALFactory } from "../secret/secret-dal"; import { fnSecretBulkInsert, fnSecretBulkUpdate } from "../secret/secret-fns"; import { TSecretQueueFactory } from "../secret/secret-queue"; @@ -36,6 +38,7 @@ type TSecretReplicationServiceFactoryDep = { secretBlindIndexDAL: Pick; secretTagDAL: Pick; secretApprovalRequestDAL: Pick; + projectMembershipDAL: Pick; secretApprovalRequestSecretDAL: Pick< TSecretApprovalRequestSecretDALFactory, "insertMany" | "insertApprovalSecretTags" @@ -60,11 +63,12 @@ export const secretReplicationServiceFactory = ({ secretApprovalRequestSecretDAL, secretApprovalRequestDAL, secretQueueService, - snapshotService + snapshotService, + projectMembershipDAL }: TSecretReplicationServiceFactoryDep) => { queueService.start(QueueName.SecretReplication, async (job) => { logger.info(job.data, "Replication started"); - const { secrets, folderId, secretPath, environmentId, projectId, membershipId, pickOnlyImportIds } = job.data; + const { secrets, folderId, secretPath, environmentId, projectId, actorId, actor, pickOnlyImportIds } = job.data; let secretImports = await secretImportDAL.find({ importPath: secretPath, importEnv: environmentId, @@ -140,7 +144,13 @@ export const secretReplicationServiceFactory = ({ importedFolder.path ); // this means it should be a approval request rather than direct replication - if (policy) { + if (policy && actor === ActorType.USER) { + const membership = await projectMembershipDAL.findOne({ projectId, userId: actorId }); + if (!membership) { + logger.error("Project membership not found in %s for user %s", projectId, actorId); + return; + } + const localSecretsLatestVersions = localSecrets.map(({ id }) => id); const latestSecretVersions = await secretVersionDAL.findLatestVersionMany( importFolderId, @@ -154,7 +164,7 @@ export const secretReplicationServiceFactory = ({ policyId: policy.id, status: "open", hasMerged: false, - committerId: membershipId, + committerId: membership.id, isReplicated: true }, tx @@ -294,7 +304,8 @@ export const secretReplicationServiceFactory = ({ secrets: nestedImportSecrets, secretPath: importedFolder.path, environmentId: importedFolder.envId, - membershipId + actorId, + actor }); const folderLock = await keyStore .acquireLock([`secret-replication-${importFolderId}`], 5000) diff --git a/backend/src/services/secret/secret-queue.ts b/backend/src/services/secret/secret-queue.ts index a4533ebc3..3055c48c3 100644 --- a/backend/src/services/secret/secret-queue.ts +++ b/backend/src/services/secret/secret-queue.ts @@ -354,7 +354,8 @@ export const secretQueueFactory = ({ secrets, folderId, excludeReplication, - membershipId + actorId, + actor } = job.data; await queueService.queue( QueueName.SecretWebhook, @@ -380,7 +381,8 @@ export const secretQueueFactory = ({ secretPath, folderId, secrets, - membershipId, + actorId, + actor, excludeReplication, environmentSlug: environment }); diff --git a/backend/src/services/secret/secret-service.ts b/backend/src/services/secret/secret-service.ts index 207a3871d..35bff3772 100644 --- a/backend/src/services/secret/secret-service.ts +++ b/backend/src/services/secret/secret-service.ts @@ -149,7 +149,7 @@ export const secretServiceFactory = ({ projectId, ...inputSecret }: TCreateSecretDTO) => { - const { permission, membership } = await permissionService.getProjectPermission( + const { permission } = await permissionService.getProjectPermission( actor, actorId, projectId, @@ -238,9 +238,9 @@ export const secretServiceFactory = ({ await snapshotService.performSnapshot(folderId); await secretQueueService.syncSecrets({ secretPath: path, - // if secret service reached means there was no secret policy - // TODO(akhilmhdh): The policy based replication will fail if machine identity is used. - membershipId: membership?.id as string, + folderId: folder.id, + actorId, + actor, projectId, environmentSlug: folder.environment.slug, environmentId: folder.envId, @@ -265,7 +265,7 @@ export const secretServiceFactory = ({ projectId, ...inputSecret }: TUpdateSecretDTO) => { - const { permission, membership } = await permissionService.getProjectPermission( + const { permission } = await permissionService.getProjectPermission( actor, actorId, projectId, @@ -381,9 +381,8 @@ export const secretServiceFactory = ({ await snapshotService.performSnapshot(folderId); await secretQueueService.syncSecrets({ - // if secret service reached means there was no secret policy - // TODO(akhilmhdh): The policy based replication will fail if machine identity is used. - membershipId: membership?.id as string, + actor, + actorId, secretPath: path, folderId: folder.id, projectId, @@ -410,7 +409,7 @@ export const secretServiceFactory = ({ projectId, ...inputSecret }: TDeleteSecretDTO) => { - const { permission, membership } = await permissionService.getProjectPermission( + const { permission } = await permissionService.getProjectPermission( actor, actorId, projectId, @@ -466,9 +465,8 @@ export const secretServiceFactory = ({ await snapshotService.performSnapshot(folderId); await secretQueueService.syncSecrets({ - // if secret service reached means there was no secret policy - // TODO(akhilmhdh): The policy based replication will fail if machine identity is used. - membershipId: membership?.id as string, + actor, + actorId, secretPath: path, folderId: folder.id, projectId, @@ -703,7 +701,7 @@ export const secretServiceFactory = ({ projectId, secrets: inputSecrets }: TCreateBulkSecretDTO) => { - const { permission, membership } = await permissionService.getProjectPermission( + const { permission } = await permissionService.getProjectPermission( actor, actorId, projectId, @@ -768,9 +766,8 @@ export const secretServiceFactory = ({ await snapshotService.performSnapshot(folderId); await secretQueueService.syncSecrets({ - // if secret service reached means there was no secret policy - // TODO(akhilmhdh): The policy based replication will fail if machine identity is used. - membershipId: membership?.id as string, + actor, + actorId, secretPath: path, folderId: folder.id, projectId, @@ -792,7 +789,7 @@ export const secretServiceFactory = ({ projectId, secrets: inputSecrets }: TUpdateBulkSecretDTO) => { - const { permission, membership } = await permissionService.getProjectPermission( + const { permission } = await permissionService.getProjectPermission( actor, actorId, projectId, @@ -878,9 +875,8 @@ export const secretServiceFactory = ({ await snapshotService.performSnapshot(folderId); await secretQueueService.syncSecrets({ - // if secret service reached means there was no secret policy - // TODO(akhilmhdh): The policy based replication will fail if machine identity is used. - membershipId: membership?.id as string, + actor, + actorId, secretPath: path, folderId: folder.id, projectId, @@ -902,7 +898,7 @@ export const secretServiceFactory = ({ actorAuthMethod, actorOrgId }: TDeleteBulkSecretDTO) => { - const { permission, membership } = await permissionService.getProjectPermission( + const { permission } = await permissionService.getProjectPermission( actor, actorId, projectId, @@ -952,9 +948,8 @@ export const secretServiceFactory = ({ await snapshotService.performSnapshot(folderId); await secretQueueService.syncSecrets({ - // if secret service reached means there was no secret policy - // TODO(akhilmhdh): The policy based replication will fail if machine identity is used. - membershipId: membership?.id as string, + actor, + actorId, secretPath: path, folderId: folder.id, projectId, diff --git a/backend/src/services/secret/secret-types.ts b/backend/src/services/secret/secret-types.ts index 723aedaf4..fb62ec052 100644 --- a/backend/src/services/secret/secret-types.ts +++ b/backend/src/services/secret/secret-types.ts @@ -11,6 +11,8 @@ import { TSecretBlindIndexDALFactory } from "@app/services/secret-blind-index/se import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-folder-dal"; import { TSecretTagDALFactory } from "@app/services/secret-tag/secret-tag-dal"; +import { ActorType } from "../auth/auth-type"; + type TPartialSecret = Pick; type TPartialInputSecret = Pick; @@ -388,7 +390,8 @@ export type TSyncSecretsDTO = { : { environmentId: string; folderId: string; - membershipId: string; + actor: ActorType; + actorId: string; // used for import creation to trigger replication pickOnlyImportIds?: string[]; secrets: {