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

View File

@@ -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;

View File

@@ -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<TProjectDALFactory, "findById" | "findProjectWithOrg">;
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
projectSlackConfigDAL: Pick<TProjectSlackConfigDALFactory, "getIntegrationDetailsByProject">;
secretApprovalRequest: TSecretApprovalRequests;
secretPath: string;
slackIntegrationDAL: Pick<TSlackIntegrationDALFactory, "findOne">;
userDAL: Pick<TUserDALFactory, "findById">;
};
@@ -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
});

View File

@@ -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<TSecretVersionV2DALFactory, "insertMany" | "findLatestVersionMany">;
secretVersionTagV2BridgeDAL: Pick<TSecretVersionV2TagDALFactory, "insertMany">;
secretApprovalPolicyDAL: Pick<TSecretApprovalPolicyDALFactory, "findById">;
slackIntegrationDAL: Pick<TSlackIntegrationDALFactory, "findOne">;
projectSlackConfigDAL: Pick<TProjectSlackConfigDALFactory, "getIntegrationDetailsByProject">;
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
};
@@ -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({

View File

@@ -881,7 +881,7 @@ export const registerRoutes = async (
projectEnvDAL,
userDAL,
licenseService,
slackIntegrationDAL
projectSlackConfigDAL
});
const secretService = secretServiceFactory({

View File

@@ -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;
}
});

View File

@@ -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<typeof projectSlackConfigDALFactory>;
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 };
};

View File

@@ -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<TSlackIntegrationDALFactory, "findOne">;
projectSlackConfigDAL: Pick<TProjectSlackConfigDALFactory, "getIntegrationDetailsByProject">;
projectDAL: Pick<TProjectDALFactory, "findById">;
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
feature: SlackTriggerFeature;
}) => {
const project = await projectDAL.findById(projectId);
const slackIntegration = await slackIntegrationDAL.findOne({
projectId
});
const slackIntegration = await projectSlackConfigDAL.getIntegrationDetailsByProject(project.id);
if (!slackIntegration) {
return;

View File

@@ -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 } = {

View File

@@ -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"
}

View File

@@ -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;

View File

@@ -442,23 +442,23 @@ export const LogsTableRow = ({ auditLog }: Props) => {
<p>{`Certificate Template ID: ${event.metadata.certificateTemplateId}`}</p>
</Td>
);
case EventType.UPDATE_SLACK_INTEGRATION:
case EventType.GET_PROJECT_SLACK_CONFIG:
return (
<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 Channels: ${event.metadata.accessRequestChannels}`}</p>
<p>{`Secret Approval Request Notification Status: ${event.metadata.isSecretRequestNotificationEnabled}`}</p>
<p>{`Secret Request Channels: ${event.metadata.secretRequestChannels}`}</p>
</Td>
);
case EventType.DELETE_SLACK_INTEGRATION:
case EventType.GET_SLACK_INTEGRATION:
return (
<Td>
<p>{`Slack integration ID: ${event.metadata.id}`}</p>
</Td>
);
default:
return <Td />;
}