diff --git a/backend/src/services/secret-sync/secret-sync-service.ts b/backend/src/services/secret-sync/secret-sync-service.ts index 1bb27c05a..3fdb7fea6 100644 --- a/backend/src/services/secret-sync/secret-sync-service.ts +++ b/backend/src/services/secret-sync/secret-sync-service.ts @@ -89,7 +89,17 @@ export const secretSyncServiceFactory = ({ projectId }); - return secretSyncs as TSecretSync[]; + return secretSyncs.filter((secretSync) => + permission.can( + ProjectPermissionSecretSyncActions.Read, + secretSync.environment && secretSync.folder + ? subject(ProjectPermissionSub.SecretSyncs, { + environment: secretSync.environment.slug, + secretPath: secretSync.folder.path + }) + : ProjectPermissionSub.SecretSyncs + ) + ) as TSecretSync[]; }; const listSecretSyncsBySecretPath = async ( @@ -105,7 +115,15 @@ export const secretSyncServiceFactory = ({ projectId }); - if (permission.cannot(ProjectPermissionSecretSyncActions.Read, ProjectPermissionSub.SecretSyncs)) { + if ( + permission.cannot( + ProjectPermissionSecretSyncActions.Read, + subject(ProjectPermissionSub.SecretSyncs, { + environment, + secretPath + }) + ) + ) { return []; } @@ -142,7 +160,12 @@ export const secretSyncServiceFactory = ({ ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionSecretSyncActions.Read, - ProjectPermissionSub.SecretSyncs + secretSync.environment && secretSync.folder + ? subject(ProjectPermissionSub.SecretSyncs, { + environment: secretSync.environment.slug, + secretPath: secretSync.folder.path + }) + : ProjectPermissionSub.SecretSyncs ); if (secretSync.connection.app !== SECRET_SYNC_CONNECTION_MAP[destination]) @@ -179,7 +202,12 @@ export const secretSyncServiceFactory = ({ ForbiddenError.from(permission).throwUnlessCan( ProjectPermissionSecretSyncActions.Read, - ProjectPermissionSub.SecretSyncs + secretSync.environment && secretSync.folder + ? subject(ProjectPermissionSub.SecretSyncs, { + environment: secretSync.environment.slug, + secretPath: secretSync.folder.path + }) + : ProjectPermissionSub.SecretSyncs ); if (secretSync.connection.app !== SECRET_SYNC_CONNECTION_MAP[destination]) diff --git a/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx b/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx index 6d95c403c..471246d04 100644 --- a/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx +++ b/frontend/src/pages/project/RoleDetailsBySlugPage/components/ProjectRoleModifySection.utils.tsx @@ -524,6 +524,36 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => { return; } + if (subject === ProjectPermissionSub.SecretSyncs) { + const canRead = action.includes(ProjectPermissionSecretSyncActions.Read); + const canEdit = action.includes(ProjectPermissionSecretSyncActions.Edit); + const canDelete = action.includes(ProjectPermissionSecretSyncActions.Delete); + const canCreate = action.includes(ProjectPermissionSecretSyncActions.Create); + const canSyncSecrets = action.includes(ProjectPermissionSecretSyncActions.SyncSecrets); + const canImportSecrets = action.includes( + ProjectPermissionSecretSyncActions.ImportSecrets + ); + const canRemoveSecrets = action.includes( + ProjectPermissionSecretSyncActions.RemoveSecrets + ); + + if (!formVal[subject]) formVal[subject] = [{ conditions: [], inverted: false }]; + + // from above statement we are sure it won't be undefined + formVal[subject]!.push({ + [ProjectPermissionSecretSyncActions.Read]: canRead, + [ProjectPermissionSecretSyncActions.Create]: canCreate, + [ProjectPermissionSecretSyncActions.Edit]: canEdit, + [ProjectPermissionSecretSyncActions.Delete]: canDelete, + [ProjectPermissionSecretSyncActions.SyncSecrets]: canSyncSecrets, + [ProjectPermissionSecretSyncActions.ImportSecrets]: canImportSecrets, + [ProjectPermissionSecretSyncActions.RemoveSecrets]: canRemoveSecrets, + conditions: conditions ? convertCaslConditionToFormOperator(conditions) : [], + inverted + }); + return; + } + if (subject === ProjectPermissionSub.DynamicSecrets) { const canRead = action.includes(ProjectPermissionDynamicSecretActions.ReadRootCredential); const canEdit = action.includes(ProjectPermissionDynamicSecretActions.EditRootCredential); @@ -786,31 +816,6 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => { return; } - if (subject === ProjectPermissionSub.SecretSyncs) { - const canRead = action.includes(ProjectPermissionSecretSyncActions.Read); - const canEdit = action.includes(ProjectPermissionSecretSyncActions.Edit); - const canDelete = action.includes(ProjectPermissionSecretSyncActions.Delete); - const canCreate = action.includes(ProjectPermissionSecretSyncActions.Create); - const canSyncSecrets = action.includes(ProjectPermissionSecretSyncActions.SyncSecrets); - const canImportSecrets = action.includes(ProjectPermissionSecretSyncActions.ImportSecrets); - const canRemoveSecrets = action.includes(ProjectPermissionSecretSyncActions.RemoveSecrets); - - if (!formVal[subject]) formVal[subject] = [{ conditions: [], inverted: false }]; - - // from above statement we are sure it won't be undefined - if (canRead) formVal[subject]![0][ProjectPermissionSecretSyncActions.Read] = true; - if (canEdit) formVal[subject]![0][ProjectPermissionSecretSyncActions.Edit] = true; - if (canCreate) formVal[subject]![0][ProjectPermissionSecretSyncActions.Create] = true; - if (canDelete) formVal[subject]![0][ProjectPermissionSecretSyncActions.Delete] = true; - if (canSyncSecrets) - formVal[subject]![0][ProjectPermissionSecretSyncActions.SyncSecrets] = true; - if (canImportSecrets) - formVal[subject]![0][ProjectPermissionSecretSyncActions.ImportSecrets] = true; - if (canRemoveSecrets) - formVal[subject]![0][ProjectPermissionSecretSyncActions.RemoveSecrets] = true; - return; - } - if (subject === ProjectPermissionSub.SecretScanningDataSources) { const canRead = action.includes(ProjectPermissionSecretScanningDataSourceActions.Read); const canEdit = action.includes(ProjectPermissionSecretScanningDataSourceActions.Edit); diff --git a/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncTable/SecretSyncRow.tsx b/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncTable/SecretSyncRow.tsx index ddc74b128..3cec5694c 100644 --- a/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncTable/SecretSyncRow.tsx +++ b/frontend/src/pages/secret-manager/IntegrationsListPage/components/SecretSyncsTab/SecretSyncTable/SecretSyncRow.tsx @@ -1,4 +1,5 @@ import { useCallback, useMemo } from "react"; +import { subject } from "@casl/ability"; import { faBan, faCalendarCheck, @@ -117,6 +118,14 @@ export const SecretSyncRow = ({ const destinationDetails = SECRET_SYNC_MAP[destination]; + const permissionSubject = + environment && folder + ? subject(ProjectPermissionSub.SecretSyncs, { + environment: environment.slug, + secretPath: folder.path + }) + : ProjectPermissionSub.SecretSyncs; + return (