diff --git a/backend/src/services/secret-import/secret-import-dal.ts b/backend/src/services/secret-import/secret-import-dal.ts index 933a78c21..2732c8eca 100644 --- a/backend/src/services/secret-import/secret-import-dal.ts +++ b/backend/src/services/secret-import/secret-import-dal.ts @@ -187,8 +187,9 @@ export const secretImportDALFactory = (db: TDbClient) => { .join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`) .select( knexInstance.ref("name").withSchema(TableName.Environment).as("envName"), + knexInstance.ref("slug").withSchema(TableName.Environment).as("envSlug"), knexInstance.ref("name").withSchema(TableName.SecretFolder).as("folderName"), - knexInstance.ref("parentId").withSchema(TableName.SecretFolder).as("parentFolderId") + knexInstance.ref("id").withSchema(TableName.SecretFolder).as("folderId") ); const secretReferences = await knexInstance(TableName.SecretReferenceV2) @@ -201,18 +202,23 @@ export const secretImportDALFactory = (db: TDbClient) => { knexInstance.ref("key").withSchema(TableName.SecretV2).as("secretId"), knexInstance.ref("name").withSchema(TableName.SecretFolder).as("folderName"), knexInstance.ref("name").withSchema(TableName.Environment).as("envName"), - knexInstance.ref("parentId").withSchema(TableName.SecretFolder).as("parentFolderId") + knexInstance.ref("slug").withSchema(TableName.Environment).as("envSlug"), + knexInstance.ref("id").withSchema(TableName.SecretFolder).as("folderId") ); - const folderResults = folderImports.map(({ envName, folderName, parentFolderId }) => ({ + const folderResults = folderImports.map(({ envName, envSlug, folderName, folderId }) => ({ envName, - folderName: parentFolderId ? folderName : "/" + envSlug, + folderName, + folderId })); - const secretResults = secretReferences.map(({ envName, secretId, folderName, parentFolderId }) => ({ + const secretResults = secretReferences.map(({ envName, envSlug, secretId, folderName, folderId }) => ({ envName, + envSlug, secretId, - folderName: parentFolderId ? folderName : "/" + folderName, + folderId })); type ResultItem = FolderResult | SecretResult; @@ -220,8 +226,12 @@ export const secretImportDALFactory = (db: TDbClient) => { type EnvFolderMap = { [envName: string]: { - [folderName: string]: { - secrets: string[]; + envSlug: string; + folders: { + [folderName: string]: { + secrets: string[]; + folderId: string; + }; }; }; }; @@ -229,19 +239,23 @@ export const secretImportDALFactory = (db: TDbClient) => { const groupedByEnv = allResults.reduce((acc, item) => { const env = item.envName; const folder = item.folderName; + const { envSlug } = item; const updatedAcc = { ...acc }; if (!updatedAcc[env]) { - updatedAcc[env] = {}; + updatedAcc[env] = { + envSlug, + folders: {} + }; } - if (!updatedAcc[env][folder]) { - updatedAcc[env][folder] = { secrets: [] }; + if (!updatedAcc[env].folders[folder]) { + updatedAcc[env].folders[folder] = { secrets: [], folderId: item.folderId }; } if ("secretId" in item && item.secretId) { - updatedAcc[env][folder].secrets = [...updatedAcc[env][folder].secrets, item.secretId]; + updatedAcc[env].folders[folder].secrets = [...updatedAcc[env].folders[folder].secrets, item.secretId]; } return updatedAcc; @@ -250,18 +264,20 @@ export const secretImportDALFactory = (db: TDbClient) => { const formattedResult: EnvInfo[] = Object.keys(groupedByEnv).map((envName) => { const envData = groupedByEnv[envName]; - const folders: FolderInfo[] = Object.keys(envData).map((folderName) => { - const folderData = envData[folderName]; + const folders: FolderInfo[] = Object.keys(envData.folders).map((folderName) => { + const folderData = envData.folders[folderName]; const hasSecrets = folderData.secrets.length > 0; return { folderName, + folderId: folderData.folderId, ...(hasSecrets && { secrets: folderData.secrets }) }; }); return { envName, + envSlug: envData.envSlug, folders }; }); diff --git a/backend/src/services/secret-import/secret-import-service.ts b/backend/src/services/secret-import/secret-import-service.ts index 31450513e..2d2a71de2 100644 --- a/backend/src/services/secret-import/secret-import-service.ts +++ b/backend/src/services/secret-import/secret-import-service.ts @@ -27,6 +27,7 @@ import { decryptSecretRaw } from "../secret/secret-fns"; import { TSecretQueueFactory } from "../secret/secret-queue"; import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal"; import { TSecretV2BridgeDALFactory } from "../secret-v2-bridge/secret-v2-bridge-dal"; +import { recursivelyGetSecretPaths } from "../secret-v2-bridge/secret-v2-bridge-fns"; import { TSecretImportDALFactory } from "./secret-import-dal"; import { fnSecretsFromImports, fnSecretsV2FromImports } from "./secret-import-fns"; import { @@ -38,7 +39,6 @@ import { TResyncSecretImportReplicationDTO, TUpdateSecretImportDTO } from "./secret-import-types"; -import { logger } from "@app/lib/logger"; type TSecretImportServiceFactoryDep = { secretImportDAL: TSecretImportDALFactory; @@ -823,8 +823,30 @@ export const secretImportServiceFactory = ({ }); const importedBy = await secretImportDAL.getFolderIsImportedBy(secretPath, folder.envId, environment, projectId); - logger.info("importedBy", JSON.stringify(importedBy)); - return importedBy; + + const deepPaths: { path: string; folderId: string }[] = []; + + await Promise.all( + importedBy.map(async (el) => { + const envDeepPaths = await recursivelyGetSecretPaths({ + folderDAL, + projectEnvDAL, + projectId, + environment: el.envSlug, + currentPath: "/" + }); + deepPaths.push(...envDeepPaths); + }) + ); + + return importedBy.map((el) => ({ + ...el, + folders: el.folders.map((folderItem) => ({ + folderId: folderItem.folderId, + secrets: folderItem.secrets, + folderName: deepPaths.find((p) => p.folderId === folderItem.folderId)?.path || `...${folderItem.folderName}` + })) + })); }; return { diff --git a/backend/src/services/secret-import/secret-import-types.ts b/backend/src/services/secret-import/secret-import-types.ts index 62f8eebd3..b598b2530 100644 --- a/backend/src/services/secret-import/secret-import-types.ts +++ b/backend/src/services/secret-import/secret-import-types.ts @@ -49,20 +49,27 @@ export type TGetSecretsFromImportDTO = { export type FolderResult = { envName: string; folderName: string; + folderId: string; + envSlug: string; }; export type SecretResult = { envName: string; secretId: string; folderName: string; + folderId: string; + envSlug: string; }; export type FolderInfo = { folderName: string; secrets?: string[]; + folderId: string; + envSlug?: string; }; export type EnvInfo = { envName: string; + envSlug: string; folders: FolderInfo[]; }; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ReplicateFolderFromBoard/SecretTreeView.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ReplicateFolderFromBoard/SecretTreeView.tsx index 4119f54e3..eba5e75d7 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ReplicateFolderFromBoard/SecretTreeView.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/ReplicateFolderFromBoard/SecretTreeView.tsx @@ -41,6 +41,7 @@ interface FolderProps { isExpanded?: boolean; level: number; basePath?: string; + isDisabled?: boolean; } interface TreeViewProps { @@ -48,6 +49,7 @@ interface TreeViewProps { basePath?: string; className?: string; onChange: (items: SecretItem[]) => void; + isDisabled?: boolean; } const getAllItemsInFolder = (folder: FolderStructure): SecretItem[] => { @@ -81,7 +83,8 @@ const Folder: React.FC = ({ onFolderSelect, isExpanded = false, level, - basePath + basePath, + isDisabled = false }) => { const [open, setOpen] = useState(isExpanded); const displayName = useMemo(() => getDisplayName(name), [name]); @@ -127,13 +130,16 @@ const Folder: React.FC = ({ className={`h-4 w-4 text-${level === 0 ? "mineshaft-300" : "yellow"}`} /> - + {!isDisabled && ( + + )}