From 8c03c160a9b3ec659950ecd5847392f867946def Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Wed, 4 Sep 2024 01:48:08 +0800 Subject: [PATCH] misc: implemented secret approval request and project audit logs --- .../ee/services/audit-log/audit-log-types.ts | 27 ++++++++++++++++-- .../secret-approval-request-fns.ts | 8 +++--- .../secret-approval-request-service.ts | 16 +++++------ backend/src/server/routes/index.ts | 2 +- .../src/server/routes/v1/project-router.ts | 28 +++++++++++++++++++ .../slack/project-slack-config-dal.ts | 18 ++++++++++-- backend/src/services/slack/slack-fns.ts | 10 +++---- .../src/hooks/api/auditLogs/constants.tsx | 6 ++-- frontend/src/hooks/api/auditLogs/enums.tsx | 6 ++-- frontend/src/hooks/api/auditLogs/types.tsx | 21 +++++--------- .../AuditLogsPage/components/LogsTableRow.tsx | 18 ++++++------ 11 files changed, 106 insertions(+), 54 deletions(-) diff --git a/backend/src/ee/services/audit-log/audit-log-types.ts b/backend/src/ee/services/audit-log/audit-log-types.ts index 29f5e99bb..b57505f60 100644 --- a/backend/src/ee/services/audit-log/audit-log-types.ts +++ b/backend/src/ee/services/audit-log/audit-log-types.ts @@ -173,7 +173,9 @@ export enum EventType { ATTEMPT_CREATE_SLACK_INTEGRATION = "attempt-create-slack-integration", GET_SLACK_INTEGRATION = "get-slack-integration", UPDATE_SLACK_INTEGRATION = "update-slack-integration", - DELETE_SLACK_INTEGRATION = "delete-slack-integration" + DELETE_SLACK_INTEGRATION = "delete-slack-integration", + GET_PROJECT_SLACK_CONFIG = "get-project-slack-config", + UPDATE_PROJECT_SLACK_CONFIG = "update-project-slack-config" } interface UserActorMetadata { @@ -1481,6 +1483,25 @@ interface GetSlackIntegration { }; } +interface UpdateProjectSlackConfig { + type: EventType.UPDATE_PROJECT_SLACK_CONFIG; + metadata: { + id: string; + slackIntegrationId: string; + isAccessRequestNotificationEnabled: boolean; + accessRequestChannels: string; + isSecretRequestNotificationEnabled: boolean; + secretRequestChannels: string; + }; +} + +interface GetProjectSlackConfig { + type: EventType.GET_PROJECT_SLACK_CONFIG; + metadata: { + id: string; + }; +} + export type Event = | GetSecretsEvent | GetSecretEvent @@ -1615,4 +1636,6 @@ export type Event = | AttemptCreateSlackIntegration | UpdateSlackIntegration | DeleteSlackIntegration - | GetSlackIntegration; + | GetSlackIntegration + | UpdateProjectSlackConfig + | GetProjectSlackConfig; diff --git a/backend/src/ee/services/secret-approval-request/secret-approval-request-fns.ts b/backend/src/ee/services/secret-approval-request/secret-approval-request-fns.ts index ddedceac1..466b4b94f 100644 --- a/backend/src/ee/services/secret-approval-request/secret-approval-request-fns.ts +++ b/backend/src/ee/services/secret-approval-request/secret-approval-request-fns.ts @@ -2,8 +2,8 @@ import { TSecretApprovalRequests } from "@app/db/schemas"; import { getConfig } from "@app/lib/config/env"; import { TKmsServiceFactory } from "@app/services/kms/kms-service"; import { TProjectDALFactory } from "@app/services/project/project-dal"; +import { TProjectSlackConfigDALFactory } from "@app/services/slack/project-slack-config-dal"; import { triggerSlackNotification } from "@app/services/slack/slack-fns"; -import { TSlackIntegrationDALFactory } from "@app/services/slack/slack-integration-dal"; import { SlackTriggerFeature } from "@app/services/slack/slack-types"; import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service"; import { TUserDALFactory } from "@app/services/user/user-dal"; @@ -23,9 +23,9 @@ type TTriggerSecretApprovalSlackNotif = { projectId: string; projectDAL: Pick; kmsService: Pick; + projectSlackConfigDAL: Pick; secretApprovalRequest: TSecretApprovalRequests; secretPath: string; - slackIntegrationDAL: Pick; userDAL: Pick; }; @@ -34,7 +34,7 @@ export const triggerSecretApprovalSlackNotif = async ({ projectDAL, kmsService, secretApprovalRequest, - slackIntegrationDAL, + projectSlackConfigDAL, userDAL, environment, secretPath @@ -74,8 +74,8 @@ export const triggerSecretApprovalSlackNotif = async ({ projectId, projectDAL, kmsService, - slackIntegrationDAL, payloadMessage: messageBody, + projectSlackConfigDAL, payloadBlocks, feature: SlackTriggerFeature.SECRET_APPROVAL }); 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 38ce76e08..cff973420 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 @@ -47,7 +47,7 @@ import { } from "@app/services/secret-v2-bridge/secret-v2-bridge-fns"; import { TSecretVersionV2DALFactory } from "@app/services/secret-v2-bridge/secret-version-dal"; import { TSecretVersionV2TagDALFactory } from "@app/services/secret-v2-bridge/secret-version-tag-dal"; -import { TSlackIntegrationDALFactory } from "@app/services/slack/slack-integration-dal"; +import { TProjectSlackConfigDALFactory } from "@app/services/slack/project-slack-config-dal"; import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service"; import { TUserDALFactory } from "@app/services/user/user-dal"; @@ -105,7 +105,7 @@ type TSecretApprovalRequestServiceFactoryDep = { secretVersionV2BridgeDAL: Pick; secretVersionTagV2BridgeDAL: Pick; secretApprovalPolicyDAL: Pick; - slackIntegrationDAL: Pick; + projectSlackConfigDAL: Pick; licenseService: Pick; }; @@ -134,8 +134,8 @@ export const secretApprovalRequestServiceFactory = ({ secretV2BridgeDAL, secretVersionV2BridgeDAL, secretVersionTagV2BridgeDAL, - slackIntegrationDAL, - licenseService + licenseService, + projectSlackConfigDAL }: TSecretApprovalRequestServiceFactoryDep) => { const requestCount = async ({ projectId, actor, actorId, actorOrgId, actorAuthMethod }: TApprovalRequestCountDTO) => { if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); @@ -1080,8 +1080,8 @@ export const secretApprovalRequestServiceFactory = ({ projectDAL, kmsService, secretApprovalRequest, - slackIntegrationDAL, - userDAL + userDAL, + projectSlackConfigDAL }); await sendApprovalEmailsFn({ @@ -1354,8 +1354,8 @@ export const secretApprovalRequestServiceFactory = ({ projectDAL, kmsService, secretApprovalRequest, - slackIntegrationDAL, - userDAL + userDAL, + projectSlackConfigDAL }); await sendApprovalEmailsFn({ diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index ba69a5c51..ede97b06d 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -881,7 +881,7 @@ export const registerRoutes = async ( projectEnvDAL, userDAL, licenseService, - slackIntegrationDAL + projectSlackConfigDAL }); const secretService = secretServiceFactory({ diff --git a/backend/src/server/routes/v1/project-router.ts b/backend/src/server/routes/v1/project-router.ts index dae8182a0..d468da0bc 100644 --- a/backend/src/server/routes/v1/project-router.ts +++ b/backend/src/server/routes/v1/project-router.ts @@ -8,6 +8,7 @@ import { UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas"; +import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { PROJECTS } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -575,6 +576,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { projectId: req.params.workspaceId }); + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: req.params.workspaceId, + event: { + type: EventType.GET_PROJECT_SLACK_CONFIG, + metadata: { + id: slackConfig.id + } + } + }); + return slackConfig; } }); @@ -618,6 +630,22 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => { ...req.body }); + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + projectId: req.params.workspaceId, + event: { + type: EventType.UPDATE_PROJECT_SLACK_CONFIG, + metadata: { + id: slackConfig.id, + slackIntegrationId: slackConfig.slackIntegrationId, + isAccessRequestNotificationEnabled: slackConfig.isAccessRequestNotificationEnabled, + accessRequestChannels: slackConfig.accessRequestChannels, + isSecretRequestNotificationEnabled: slackConfig.isSecretRequestNotificationEnabled, + secretRequestChannels: slackConfig.secretRequestChannels + } + } + }); + return slackConfig; } }); diff --git a/backend/src/services/slack/project-slack-config-dal.ts b/backend/src/services/slack/project-slack-config-dal.ts index 2c08fdeb3..276442b1b 100644 --- a/backend/src/services/slack/project-slack-config-dal.ts +++ b/backend/src/services/slack/project-slack-config-dal.ts @@ -1,11 +1,25 @@ +import { Knex } from "knex"; + import { TDbClient } from "@app/db"; import { TableName } from "@app/db/schemas"; -import { ormify } from "@app/lib/knex"; +import { ormify, selectAllTableCols } from "@app/lib/knex"; export type TProjectSlackConfigDALFactory = ReturnType; export const projectSlackConfigDALFactory = (db: TDbClient) => { const projectSlackConfigOrm = ormify(db, TableName.ProjectSlackConfigs); - return projectSlackConfigOrm; + const getIntegrationDetailsByProject = (projectId: string, tx?: Knex) => { + return (tx || db.replicaNode())(TableName.ProjectSlackConfigs) + .join( + TableName.SlackIntegrations, + `${TableName.ProjectSlackConfigs}.slackIntegrationId`, + `${TableName.SlackIntegrations}.id` + ) + .where("projectId", "=", projectId) + .select(selectAllTableCols(TableName.ProjectSlackConfigs), selectAllTableCols(TableName.SlackIntegrations)) + .first(); + }; + + return { ...projectSlackConfigOrm, getIntegrationDetailsByProject }; }; diff --git a/backend/src/services/slack/slack-fns.ts b/backend/src/services/slack/slack-fns.ts index 5c22186c6..cf28a550f 100644 --- a/backend/src/services/slack/slack-fns.ts +++ b/backend/src/services/slack/slack-fns.ts @@ -3,14 +3,14 @@ import { Block, WebClient } from "@slack/web-api"; import { TKmsServiceFactory } from "../kms/kms-service"; import { KmsDataKey } from "../kms/kms-types"; import { TProjectDALFactory } from "../project/project-dal"; -import { TSlackIntegrationDALFactory } from "./slack-integration-dal"; +import { TProjectSlackConfigDALFactory } from "./project-slack-config-dal"; import { SlackTriggerFeature } from "./slack-types"; export const triggerSlackNotification = async ({ projectId, payloadBlocks, payloadMessage, - slackIntegrationDAL, + projectSlackConfigDAL, projectDAL, kmsService, feature @@ -18,15 +18,13 @@ export const triggerSlackNotification = async ({ projectId: string; payloadBlocks: Block[]; payloadMessage: string; - slackIntegrationDAL: Pick; + projectSlackConfigDAL: Pick; projectDAL: Pick; kmsService: Pick; feature: SlackTriggerFeature; }) => { const project = await projectDAL.findById(projectId); - const slackIntegration = await slackIntegrationDAL.findOne({ - projectId - }); + const slackIntegration = await projectSlackConfigDAL.getIntegrationDetailsByProject(project.id); if (!slackIntegration) { return; diff --git a/frontend/src/hooks/api/auditLogs/constants.tsx b/frontend/src/hooks/api/auditLogs/constants.tsx index 7e59e639f..cc72cfa86 100644 --- a/frontend/src/hooks/api/auditLogs/constants.tsx +++ b/frontend/src/hooks/api/auditLogs/constants.tsx @@ -78,10 +78,8 @@ export const eventToNameMap: { [K in EventType]: string } = { "Create certificate template EST configuration", [EventType.UPDATE_CERTIFICATE_TEMPLATE_EST_CONFIG]: "Update certificate template EST configuration", - [EventType.UPDATE_SLACK_INTEGRATION]: "Update slack integration", - [EventType.DELETE_SLACK_INTEGRATION]: "Delete slack integration", - [EventType.GET_SLACK_INTEGRATION]: "Get slack integration", - [EventType.ATTEMPT_CREATE_SLACK_INTEGRATION]: "Initiate create slack integration flow" + [EventType.UPDATE_PROJECT_SLACK_CONFIG]: "Update project slack configuration", + [EventType.GET_PROJECT_SLACK_CONFIG]: "Get project slack configuration" }; export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = { diff --git a/frontend/src/hooks/api/auditLogs/enums.tsx b/frontend/src/hooks/api/auditLogs/enums.tsx index 5d58b2be1..b110e330b 100644 --- a/frontend/src/hooks/api/auditLogs/enums.tsx +++ b/frontend/src/hooks/api/auditLogs/enums.tsx @@ -90,8 +90,6 @@ export enum EventType { CREATE_CERTIFICATE_TEMPLATE_EST_CONFIG = "create-certificate-template-est-config", UPDATE_CERTIFICATE_TEMPLATE_EST_CONFIG = "update-certificate-template-est-config", GET_CERTIFICATE_TEMPLATE_EST_CONFIG = "get-certificate-template-est-config", - ATTEMPT_CREATE_SLACK_INTEGRATION = "attempt-create-slack-integration", - GET_SLACK_INTEGRATION = "get-slack-integration", - UPDATE_SLACK_INTEGRATION = "update-slack-integration", - DELETE_SLACK_INTEGRATION = "delete-slack-integration" + UPDATE_PROJECT_SLACK_CONFIG = "update-project-slack-config", + GET_PROJECT_SLACK_CONFIG = "get-project-slack-config" } diff --git a/frontend/src/hooks/api/auditLogs/types.tsx b/frontend/src/hooks/api/auditLogs/types.tsx index 959f9aaa3..85f4c2f73 100644 --- a/frontend/src/hooks/api/auditLogs/types.tsx +++ b/frontend/src/hooks/api/auditLogs/types.tsx @@ -742,10 +742,11 @@ interface GetCertificateTemplateEstConfig { }; } -interface UpdateSlackIntegration { - type: EventType.UPDATE_SLACK_INTEGRATION; +interface UpdateProjectSlackConfig { + type: EventType.UPDATE_PROJECT_SLACK_CONFIG; metadata: { id: string; + slackIntegrationId: string; isAccessRequestNotificationEnabled: boolean; accessRequestChannels: string; isSecretRequestNotificationEnabled: boolean; @@ -753,15 +754,8 @@ interface UpdateSlackIntegration { }; } -interface DeleteSlackIntegration { - type: EventType.DELETE_SLACK_INTEGRATION; - metadata: { - id: string; - }; -} - -interface GetSlackIntegration { - type: EventType.GET_SLACK_INTEGRATION; +interface GetProjectSlackConfig { + type: EventType.GET_PROJECT_SLACK_CONFIG; metadata: { id: string; }; @@ -843,9 +837,8 @@ export type Event = | UpdateCertificateTemplateEstConfig | CreateCertificateTemplateEstConfig | GetCertificateTemplateEstConfig - | UpdateSlackIntegration - | DeleteSlackIntegration - | GetSlackIntegration; + | UpdateProjectSlackConfig + | GetProjectSlackConfig; export type AuditLog = { id: string; diff --git a/frontend/src/views/Project/AuditLogsPage/components/LogsTableRow.tsx b/frontend/src/views/Project/AuditLogsPage/components/LogsTableRow.tsx index ec53eec3b..bc81e9160 100644 --- a/frontend/src/views/Project/AuditLogsPage/components/LogsTableRow.tsx +++ b/frontend/src/views/Project/AuditLogsPage/components/LogsTableRow.tsx @@ -442,23 +442,23 @@ export const LogsTableRow = ({ auditLog }: Props) => {

{`Certificate Template ID: ${event.metadata.certificateTemplateId}`}

); - case EventType.UPDATE_SLACK_INTEGRATION: + case EventType.GET_PROJECT_SLACK_CONFIG: return ( -

{`Slack integration ID: ${event.metadata.id}`}

+

{`Project Slack Config ID: ${event.metadata.id}`}

+ + ); + case EventType.UPDATE_PROJECT_SLACK_CONFIG: + return ( + +

{`Project Slack Config ID: ${event.metadata.id}`}

+

{`Slack integration ID: ${event.metadata.slackIntegrationId}`}

{`Access Request Notification Status: ${event.metadata.isAccessRequestNotificationEnabled}`}

{`Access Request Channels: ${event.metadata.accessRequestChannels}`}

{`Secret Approval Request Notification Status: ${event.metadata.isSecretRequestNotificationEnabled}`}

{`Secret Request Channels: ${event.metadata.secretRequestChannels}`}

); - case EventType.DELETE_SLACK_INTEGRATION: - case EventType.GET_SLACK_INTEGRATION: - return ( - -

{`Slack integration ID: ${event.metadata.id}`}

- - ); default: return ; }