From e959ed7fabaa355230b96de7705219d5a8a26e78 Mon Sep 17 00:00:00 2001 From: carlosmonastyrski Date: Tue, 29 Apr 2025 10:15:53 -0300 Subject: [PATCH] feat(secrets-ui): improve warning message and logic for secret-sync on secret imports --- backend/src/server/routes/index.ts | 1 + .../src/server/routes/v1/dashboard-router.ts | 6 ++--- .../secret-import/secret-import-dal.ts | 26 ++++++++++++++----- .../secret-import/secret-import-service.ts | 2 +- .../secret-import/secret-import-types.ts | 4 +-- .../secret-sync/secret-sync-service.ts | 12 ++++++--- .../DeleteActionModal/DeleteActionModal.tsx | 4 +-- frontend/src/hooks/api/dashboard/types.ts | 2 +- .../OverviewPage/OverviewPage.tsx | 2 +- .../SecretOverviewTableRow/SecretEditRow.tsx | 7 +++-- .../SecretOverviewTableRow.tsx | 2 +- .../components/ActionBar/ActionBar.tsx | 2 +- .../CollapsibleSecretImports.tsx | 20 +++++++++++--- .../components/SecretListView/SecretItem.tsx | 15 +++++------ .../SecretListView/SecretListView.tsx | 2 +- 15 files changed, 71 insertions(+), 36 deletions(-) diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index 8ceeba648..a71a69c20 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -1541,6 +1541,7 @@ export const registerRoutes = async ( const secretSyncService = secretSyncServiceFactory({ secretSyncDAL, + secretImportDAL, permissionService, appConnectionService, folderDAL, diff --git a/backend/src/server/routes/v1/dashboard-router.ts b/backend/src/server/routes/v1/dashboard-router.ts index bd5029acf..146a31cf2 100644 --- a/backend/src/server/routes/v1/dashboard-router.ts +++ b/backend/src/server/routes/v1/dashboard-router.ts @@ -155,7 +155,7 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => { .object({ secretId: z.string(), referencedSecretKey: z.string(), - referencedSecretId: z.string() + referencedSecretEnv: z.string() }) .array() .optional() @@ -658,7 +658,7 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => { .object({ secretId: z.string(), referencedSecretKey: z.string(), - referencedSecretId: z.string() + referencedSecretEnv: z.string() }) .array() .optional() @@ -945,7 +945,7 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => { const usedBySecretSyncs = secretSyncs.map((sync) => ({ name: sync.name, destination: sync.destination, - environment + environment: sync.environment?.name || environment })); if (secrets?.length || secretRotations?.length) { diff --git a/backend/src/services/secret-import/secret-import-dal.ts b/backend/src/services/secret-import/secret-import-dal.ts index 7ea276268..dbe2f6a84 100644 --- a/backend/src/services/secret-import/secret-import-dal.ts +++ b/backend/src/services/secret-import/secret-import-dal.ts @@ -171,6 +171,19 @@ export const secretImportDALFactory = (db: TDbClient) => { } }; + const getFolderImports = async (secretPath: string, environmentId: string, tx?: Knex) => { + try { + const folderImports = await (tx || db.replicaNode())(TableName.SecretImport) + .where({ importPath: secretPath, importEnv: environmentId }) + .join(TableName.SecretFolder, `${TableName.SecretImport}.folderId`, `${TableName.SecretFolder}.id`) + .join(TableName.Environment, `${TableName.SecretFolder}.envId`, `${TableName.Environment}.id`) + .select(db.ref("id").withSchema(TableName.SecretFolder).as("folderId")); + return folderImports; + } catch (error) { + throw new DatabaseError({ error, name: "get secret imports" }); + } + }; + const getFolderIsImportedBy = async ( secretPath: string, environmentId: string, @@ -204,7 +217,7 @@ export const secretImportDALFactory = (db: TDbClient) => { db.ref("slug").withSchema(TableName.Environment).as("envSlug"), db.ref("id").withSchema(TableName.SecretFolder).as("folderId"), db.ref("secretKey").withSchema(TableName.SecretReferenceV2).as("referencedSecretKey"), - db.ref("id").withSchema(TableName.SecretV2).as("referencedSecretId") + db.ref("environment").withSchema(TableName.SecretReferenceV2).as("referencedSecretEnv") ); const folderResults = folderImports.map(({ envName, envSlug, folderName, folderId }) => ({ @@ -215,14 +228,14 @@ export const secretImportDALFactory = (db: TDbClient) => { })); const secretResults = secretReferences.map( - ({ envName, envSlug, secretId, folderName, folderId, referencedSecretKey, referencedSecretId }) => ({ + ({ envName, envSlug, secretId, folderName, folderId, referencedSecretKey, referencedSecretEnv }) => ({ envName, envSlug, secretId, folderName, folderId, referencedSecretKey, - referencedSecretId + referencedSecretEnv }) ); @@ -237,7 +250,7 @@ export const secretImportDALFactory = (db: TDbClient) => { secrets: { secretId: string; referencedSecretKey: string; - referencedSecretId: string; + referencedSecretEnv: string; }[]; folderId: string; folderImported: boolean; @@ -270,7 +283,7 @@ export const secretImportDALFactory = (db: TDbClient) => { { secretId: item.secretId, referencedSecretKey: item.referencedSecretKey, - referencedSecretId: item.referencedSecretId + referencedSecretEnv: item.referencedSecretEnv } ]; } else { @@ -316,6 +329,7 @@ export const secretImportDALFactory = (db: TDbClient) => { findLastImportPosition, updateAllPosition, getProjectImportCount, - getFolderIsImportedBy + getFolderIsImportedBy, + getFolderImports }; }; diff --git a/backend/src/services/secret-import/secret-import-service.ts b/backend/src/services/secret-import/secret-import-service.ts index 998d8682a..5078496d6 100644 --- a/backend/src/services/secret-import/secret-import-service.ts +++ b/backend/src/services/secret-import/secret-import-service.ts @@ -878,7 +878,7 @@ export const secretImportServiceFactory = ({ .map((otherSecret) => ({ secretId: secret.secretKey, referencedSecretKey: otherSecret.secretKey, - referencedSecretId: otherSecret.id + referencedSecretEnv: environment })); }) || []; if (locallyReferenced.length > 0) { diff --git a/backend/src/services/secret-import/secret-import-types.ts b/backend/src/services/secret-import/secret-import-types.ts index 407372267..41ddbc9e2 100644 --- a/backend/src/services/secret-import/secret-import-types.ts +++ b/backend/src/services/secret-import/secret-import-types.ts @@ -56,12 +56,12 @@ export type FolderResult = { export type SecretResult = { secretId: string; referencedSecretKey: string; - referencedSecretId: string; + referencedSecretEnv: string; } & FolderResult; export type FolderInfo = { folderName: string; - secrets?: { secretId: string; referencedSecretKey: string; referencedSecretId: string }[]; + secrets?: { secretId: string; referencedSecretKey: string; referencedSecretEnv: string }[]; folderId: string; folderImported: boolean; envSlug?: string; diff --git a/backend/src/services/secret-sync/secret-sync-service.ts b/backend/src/services/secret-sync/secret-sync-service.ts index a19ebe6f7..db350f785 100644 --- a/backend/src/services/secret-sync/secret-sync-service.ts +++ b/backend/src/services/secret-sync/secret-sync-service.ts @@ -32,12 +32,14 @@ import { TUpdateSecretSyncDTO } from "@app/services/secret-sync/secret-sync-types"; +import { TSecretImportDALFactory } from "../secret-import/secret-import-dal"; import { TSecretSyncDALFactory } from "./secret-sync-dal"; import { SECRET_SYNC_CONNECTION_MAP, SECRET_SYNC_NAME_MAP } from "./secret-sync-maps"; import { TSecretSyncQueueFactory } from "./secret-sync-queue"; type TSecretSyncServiceFactoryDep = { secretSyncDAL: TSecretSyncDALFactory; + secretImportDAL: TSecretImportDALFactory; appConnectionService: Pick; permissionService: Pick; projectBotService: Pick; @@ -54,6 +56,7 @@ export type TSecretSyncServiceFactory = ReturnType { const { permission } = await permissionService.getProjectPermission({ @@ -106,9 +109,12 @@ export const secretSyncServiceFactory = ({ const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath); if (!folder) return []; + const folderImports = await secretImportDAL.getFolderImports(secretPath, folder.envId); + const secretSyncs = await secretSyncDAL.find({ - ...(destination && { destination }), - folderId: folder.id + $in: { + folderId: folderImports.map((folderImport) => folderImport.folderId).concat(folder.id) + } }); return secretSyncs as TSecretSync[]; diff --git a/frontend/src/components/v2/DeleteActionModal/DeleteActionModal.tsx b/frontend/src/components/v2/DeleteActionModal/DeleteActionModal.tsx index 0b0dab278..2fdb56c8c 100644 --- a/frontend/src/components/v2/DeleteActionModal/DeleteActionModal.tsx +++ b/frontend/src/components/v2/DeleteActionModal/DeleteActionModal.tsx @@ -33,7 +33,7 @@ export const DeleteActionModal = ({ buttonText = "Delete", formContent, deletionMessage, - buttonColorSchema, + buttonColorSchema = "danger", children }: Props): JSX.Element => { const [inputData, setInputData] = useState(""); @@ -69,7 +69,7 @@ export const DeleteActionModal = ({