misc: implemented secret approval request and project audit logs

This commit is contained in:
Sheen Capadngan
2024-09-04 01:48:08 +08:00
parent 604b0467f9
commit 8c03c160a9
11 changed files with 106 additions and 54 deletions
@@ -173,7 +173,9 @@ export enum EventType {
ATTEMPT_CREATE_SLACK_INTEGRATION = "attempt-create-slack-integration", ATTEMPT_CREATE_SLACK_INTEGRATION = "attempt-create-slack-integration",
GET_SLACK_INTEGRATION = "get-slack-integration", GET_SLACK_INTEGRATION = "get-slack-integration",
UPDATE_SLACK_INTEGRATION = "update-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 { 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 = export type Event =
| GetSecretsEvent | GetSecretsEvent
| GetSecretEvent | GetSecretEvent
@@ -1615,4 +1636,6 @@ export type Event =
| AttemptCreateSlackIntegration | AttemptCreateSlackIntegration
| UpdateSlackIntegration | UpdateSlackIntegration
| DeleteSlackIntegration | DeleteSlackIntegration
| GetSlackIntegration; | GetSlackIntegration
| UpdateProjectSlackConfig
| GetProjectSlackConfig;
@@ -2,8 +2,8 @@ import { TSecretApprovalRequests } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
import { TKmsServiceFactory } from "@app/services/kms/kms-service"; import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TProjectDALFactory } from "@app/services/project/project-dal"; 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 { 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 { SlackTriggerFeature } from "@app/services/slack/slack-types";
import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service"; import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
import { TUserDALFactory } from "@app/services/user/user-dal"; import { TUserDALFactory } from "@app/services/user/user-dal";
@@ -23,9 +23,9 @@ type TTriggerSecretApprovalSlackNotif = {
projectId: string; projectId: string;
projectDAL: Pick<TProjectDALFactory, "findById" | "findProjectWithOrg">; projectDAL: Pick<TProjectDALFactory, "findById" | "findProjectWithOrg">;
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">; kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
projectSlackConfigDAL: Pick<TProjectSlackConfigDALFactory, "getIntegrationDetailsByProject">;
secretApprovalRequest: TSecretApprovalRequests; secretApprovalRequest: TSecretApprovalRequests;
secretPath: string; secretPath: string;
slackIntegrationDAL: Pick<TSlackIntegrationDALFactory, "findOne">;
userDAL: Pick<TUserDALFactory, "findById">; userDAL: Pick<TUserDALFactory, "findById">;
}; };
@@ -34,7 +34,7 @@ export const triggerSecretApprovalSlackNotif = async ({
projectDAL, projectDAL,
kmsService, kmsService,
secretApprovalRequest, secretApprovalRequest,
slackIntegrationDAL, projectSlackConfigDAL,
userDAL, userDAL,
environment, environment,
secretPath secretPath
@@ -74,8 +74,8 @@ export const triggerSecretApprovalSlackNotif = async ({
projectId, projectId,
projectDAL, projectDAL,
kmsService, kmsService,
slackIntegrationDAL,
payloadMessage: messageBody, payloadMessage: messageBody,
projectSlackConfigDAL,
payloadBlocks, payloadBlocks,
feature: SlackTriggerFeature.SECRET_APPROVAL feature: SlackTriggerFeature.SECRET_APPROVAL
}); });
@@ -47,7 +47,7 @@ import {
} from "@app/services/secret-v2-bridge/secret-v2-bridge-fns"; } from "@app/services/secret-v2-bridge/secret-v2-bridge-fns";
import { TSecretVersionV2DALFactory } from "@app/services/secret-v2-bridge/secret-version-dal"; import { TSecretVersionV2DALFactory } from "@app/services/secret-v2-bridge/secret-version-dal";
import { TSecretVersionV2TagDALFactory } from "@app/services/secret-v2-bridge/secret-version-tag-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 { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
import { TUserDALFactory } from "@app/services/user/user-dal"; import { TUserDALFactory } from "@app/services/user/user-dal";
@@ -105,7 +105,7 @@ type TSecretApprovalRequestServiceFactoryDep = {
secretVersionV2BridgeDAL: Pick<TSecretVersionV2DALFactory, "insertMany" | "findLatestVersionMany">; secretVersionV2BridgeDAL: Pick<TSecretVersionV2DALFactory, "insertMany" | "findLatestVersionMany">;
secretVersionTagV2BridgeDAL: Pick<TSecretVersionV2TagDALFactory, "insertMany">; secretVersionTagV2BridgeDAL: Pick<TSecretVersionV2TagDALFactory, "insertMany">;
secretApprovalPolicyDAL: Pick<TSecretApprovalPolicyDALFactory, "findById">; secretApprovalPolicyDAL: Pick<TSecretApprovalPolicyDALFactory, "findById">;
slackIntegrationDAL: Pick<TSlackIntegrationDALFactory, "findOne">; projectSlackConfigDAL: Pick<TProjectSlackConfigDALFactory, "getIntegrationDetailsByProject">;
licenseService: Pick<TLicenseServiceFactory, "getPlan">; licenseService: Pick<TLicenseServiceFactory, "getPlan">;
}; };
@@ -134,8 +134,8 @@ export const secretApprovalRequestServiceFactory = ({
secretV2BridgeDAL, secretV2BridgeDAL,
secretVersionV2BridgeDAL, secretVersionV2BridgeDAL,
secretVersionTagV2BridgeDAL, secretVersionTagV2BridgeDAL,
slackIntegrationDAL, licenseService,
licenseService projectSlackConfigDAL
}: TSecretApprovalRequestServiceFactoryDep) => { }: TSecretApprovalRequestServiceFactoryDep) => {
const requestCount = async ({ projectId, actor, actorId, actorOrgId, actorAuthMethod }: TApprovalRequestCountDTO) => { const requestCount = async ({ projectId, actor, actorId, actorOrgId, actorAuthMethod }: TApprovalRequestCountDTO) => {
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" }); if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
@@ -1080,8 +1080,8 @@ export const secretApprovalRequestServiceFactory = ({
projectDAL, projectDAL,
kmsService, kmsService,
secretApprovalRequest, secretApprovalRequest,
slackIntegrationDAL, userDAL,
userDAL projectSlackConfigDAL
}); });
await sendApprovalEmailsFn({ await sendApprovalEmailsFn({
@@ -1354,8 +1354,8 @@ export const secretApprovalRequestServiceFactory = ({
projectDAL, projectDAL,
kmsService, kmsService,
secretApprovalRequest, secretApprovalRequest,
slackIntegrationDAL, userDAL,
userDAL projectSlackConfigDAL
}); });
await sendApprovalEmailsFn({ await sendApprovalEmailsFn({
+1 -1
View File
@@ -881,7 +881,7 @@ export const registerRoutes = async (
projectEnvDAL, projectEnvDAL,
userDAL, userDAL,
licenseService, licenseService,
slackIntegrationDAL projectSlackConfigDAL
}); });
const secretService = secretServiceFactory({ const secretService = secretServiceFactory({
@@ -8,6 +8,7 @@ import {
UserEncryptionKeysSchema, UserEncryptionKeysSchema,
UsersSchema UsersSchema
} from "@app/db/schemas"; } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { PROJECTS } from "@app/lib/api-docs"; import { PROJECTS } from "@app/lib/api-docs";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
@@ -575,6 +576,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
projectId: req.params.workspaceId 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; return slackConfig;
} }
}); });
@@ -618,6 +630,22 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
...req.body ...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; return slackConfig;
} }
}); });
@@ -1,11 +1,25 @@
import { Knex } from "knex";
import { TDbClient } from "@app/db"; import { TDbClient } from "@app/db";
import { TableName } from "@app/db/schemas"; import { TableName } from "@app/db/schemas";
import { ormify } from "@app/lib/knex"; import { ormify, selectAllTableCols } from "@app/lib/knex";
export type TProjectSlackConfigDALFactory = ReturnType<typeof projectSlackConfigDALFactory>; export type TProjectSlackConfigDALFactory = ReturnType<typeof projectSlackConfigDALFactory>;
export const projectSlackConfigDALFactory = (db: TDbClient) => { export const projectSlackConfigDALFactory = (db: TDbClient) => {
const projectSlackConfigOrm = ormify(db, TableName.ProjectSlackConfigs); 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 };
}; };
+4 -6
View File
@@ -3,14 +3,14 @@ import { Block, WebClient } from "@slack/web-api";
import { TKmsServiceFactory } from "../kms/kms-service"; import { TKmsServiceFactory } from "../kms/kms-service";
import { KmsDataKey } from "../kms/kms-types"; import { KmsDataKey } from "../kms/kms-types";
import { TProjectDALFactory } from "../project/project-dal"; import { TProjectDALFactory } from "../project/project-dal";
import { TSlackIntegrationDALFactory } from "./slack-integration-dal"; import { TProjectSlackConfigDALFactory } from "./project-slack-config-dal";
import { SlackTriggerFeature } from "./slack-types"; import { SlackTriggerFeature } from "./slack-types";
export const triggerSlackNotification = async ({ export const triggerSlackNotification = async ({
projectId, projectId,
payloadBlocks, payloadBlocks,
payloadMessage, payloadMessage,
slackIntegrationDAL, projectSlackConfigDAL,
projectDAL, projectDAL,
kmsService, kmsService,
feature feature
@@ -18,15 +18,13 @@ export const triggerSlackNotification = async ({
projectId: string; projectId: string;
payloadBlocks: Block[]; payloadBlocks: Block[];
payloadMessage: string; payloadMessage: string;
slackIntegrationDAL: Pick<TSlackIntegrationDALFactory, "findOne">; projectSlackConfigDAL: Pick<TProjectSlackConfigDALFactory, "getIntegrationDetailsByProject">;
projectDAL: Pick<TProjectDALFactory, "findById">; projectDAL: Pick<TProjectDALFactory, "findById">;
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">; kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
feature: SlackTriggerFeature; feature: SlackTriggerFeature;
}) => { }) => {
const project = await projectDAL.findById(projectId); const project = await projectDAL.findById(projectId);
const slackIntegration = await slackIntegrationDAL.findOne({ const slackIntegration = await projectSlackConfigDAL.getIntegrationDetailsByProject(project.id);
projectId
});
if (!slackIntegration) { if (!slackIntegration) {
return; return;
@@ -78,10 +78,8 @@ export const eventToNameMap: { [K in EventType]: string } = {
"Create certificate template EST configuration", "Create certificate template EST configuration",
[EventType.UPDATE_CERTIFICATE_TEMPLATE_EST_CONFIG]: [EventType.UPDATE_CERTIFICATE_TEMPLATE_EST_CONFIG]:
"Update certificate template EST configuration", "Update certificate template EST configuration",
[EventType.UPDATE_SLACK_INTEGRATION]: "Update slack integration", [EventType.UPDATE_PROJECT_SLACK_CONFIG]: "Update project slack configuration",
[EventType.DELETE_SLACK_INTEGRATION]: "Delete slack integration", [EventType.GET_PROJECT_SLACK_CONFIG]: "Get project slack configuration"
[EventType.GET_SLACK_INTEGRATION]: "Get slack integration",
[EventType.ATTEMPT_CREATE_SLACK_INTEGRATION]: "Initiate create slack integration flow"
}; };
export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = { export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = {
+2 -4
View File
@@ -90,8 +90,6 @@ export enum EventType {
CREATE_CERTIFICATE_TEMPLATE_EST_CONFIG = "create-certificate-template-est-config", CREATE_CERTIFICATE_TEMPLATE_EST_CONFIG = "create-certificate-template-est-config",
UPDATE_CERTIFICATE_TEMPLATE_EST_CONFIG = "update-certificate-template-est-config", UPDATE_CERTIFICATE_TEMPLATE_EST_CONFIG = "update-certificate-template-est-config",
GET_CERTIFICATE_TEMPLATE_EST_CONFIG = "get-certificate-template-est-config", GET_CERTIFICATE_TEMPLATE_EST_CONFIG = "get-certificate-template-est-config",
ATTEMPT_CREATE_SLACK_INTEGRATION = "attempt-create-slack-integration", UPDATE_PROJECT_SLACK_CONFIG = "update-project-slack-config",
GET_SLACK_INTEGRATION = "get-slack-integration", GET_PROJECT_SLACK_CONFIG = "get-project-slack-config"
UPDATE_SLACK_INTEGRATION = "update-slack-integration",
DELETE_SLACK_INTEGRATION = "delete-slack-integration"
} }
+7 -14
View File
@@ -742,10 +742,11 @@ interface GetCertificateTemplateEstConfig {
}; };
} }
interface UpdateSlackIntegration { interface UpdateProjectSlackConfig {
type: EventType.UPDATE_SLACK_INTEGRATION; type: EventType.UPDATE_PROJECT_SLACK_CONFIG;
metadata: { metadata: {
id: string; id: string;
slackIntegrationId: string;
isAccessRequestNotificationEnabled: boolean; isAccessRequestNotificationEnabled: boolean;
accessRequestChannels: string; accessRequestChannels: string;
isSecretRequestNotificationEnabled: boolean; isSecretRequestNotificationEnabled: boolean;
@@ -753,15 +754,8 @@ interface UpdateSlackIntegration {
}; };
} }
interface DeleteSlackIntegration { interface GetProjectSlackConfig {
type: EventType.DELETE_SLACK_INTEGRATION; type: EventType.GET_PROJECT_SLACK_CONFIG;
metadata: {
id: string;
};
}
interface GetSlackIntegration {
type: EventType.GET_SLACK_INTEGRATION;
metadata: { metadata: {
id: string; id: string;
}; };
@@ -843,9 +837,8 @@ export type Event =
| UpdateCertificateTemplateEstConfig | UpdateCertificateTemplateEstConfig
| CreateCertificateTemplateEstConfig | CreateCertificateTemplateEstConfig
| GetCertificateTemplateEstConfig | GetCertificateTemplateEstConfig
| UpdateSlackIntegration | UpdateProjectSlackConfig
| DeleteSlackIntegration | GetProjectSlackConfig;
| GetSlackIntegration;
export type AuditLog = { export type AuditLog = {
id: string; id: string;
@@ -442,23 +442,23 @@ export const LogsTableRow = ({ auditLog }: Props) => {
<p>{`Certificate Template ID: ${event.metadata.certificateTemplateId}`}</p> <p>{`Certificate Template ID: ${event.metadata.certificateTemplateId}`}</p>
</Td> </Td>
); );
case EventType.UPDATE_SLACK_INTEGRATION: case EventType.GET_PROJECT_SLACK_CONFIG:
return ( return (
<Td> <Td>
<p>{`Slack integration ID: ${event.metadata.id}`}</p> <p>{`Project Slack Config ID: ${event.metadata.id}`}</p>
</Td>
);
case EventType.UPDATE_PROJECT_SLACK_CONFIG:
return (
<Td>
<p>{`Project Slack Config ID: ${event.metadata.id}`}</p>
<p>{`Slack integration ID: ${event.metadata.slackIntegrationId}`}</p>
<p>{`Access Request Notification Status: ${event.metadata.isAccessRequestNotificationEnabled}`}</p> <p>{`Access Request Notification Status: ${event.metadata.isAccessRequestNotificationEnabled}`}</p>
<p>{`Access Request Channels: ${event.metadata.accessRequestChannels}`}</p> <p>{`Access Request Channels: ${event.metadata.accessRequestChannels}`}</p>
<p>{`Secret Approval Request Notification Status: ${event.metadata.isSecretRequestNotificationEnabled}`}</p> <p>{`Secret Approval Request Notification Status: ${event.metadata.isSecretRequestNotificationEnabled}`}</p>
<p>{`Secret Request Channels: ${event.metadata.secretRequestChannels}`}</p> <p>{`Secret Request Channels: ${event.metadata.secretRequestChannels}`}</p>
</Td> </Td>
); );
case EventType.DELETE_SLACK_INTEGRATION:
case EventType.GET_SLACK_INTEGRATION:
return (
<Td>
<p>{`Slack integration ID: ${event.metadata.id}`}</p>
</Td>
);
default: default:
return <Td />; return <Td />;
} }