misc: addressed review comments

This commit is contained in:
Sheen Capadngan
2024-09-11 00:11:19 +08:00
parent ffaf145317
commit 7a36badb23
13 changed files with 212 additions and 275 deletions
+88 -52
View File
@@ -1,53 +1,14 @@
import { Block, WebClient } from "@slack/web-api";
import { WebClient } from "@slack/web-api";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { TKmsServiceFactory } from "../kms/kms-service";
import { KmsDataKey } from "../kms/kms-types";
import { TProjectDALFactory } from "../project/project-dal";
import { TProjectSlackConfigDALFactory } from "./project-slack-config-dal";
import { SlackTriggerFeature } from "./slack-types";
export const getCustomSlackBotManifest = () => {
const appCfg = getConfig();
return {
display_information: {
name: "Infisical",
description: "Get real-time Infisical updates in Slack",
background_color: "#c2d62b",
long_description: `This Slack application is designed specifically for use with your self-hosted Infisical instance, allowing seamless integration between your Infisical projects and your Slack workspace. With this integration, your team can stay up-to-date with the latest events, changes, and notifications directly inside Slack.
- Notifications: Receive real-time updates and alerts about critical events in your Infisical projects. Whether it's a new project being created, updates to secrets, or changes to your team's configuration, you will be promptly notified within the designated Slack channels of your choice.
- Customization: Tailor the notifications to your team's specific needs by configuring which types of events trigger alerts and in which channels they are sent.
- Collaboration: Keep your entire team in the loop with notifications that help facilitate more efficient collaboration by ensuring that everyone is aware of important developments in your Infisical projects.
By integrating Infisical with Slack, you can enhance your workflow by combining the power of secure secrets management with the communication capabilities of Slack.`
},
features: {
app_home: {
home_tab_enabled: false,
messages_tab_enabled: false,
messages_tab_read_only_enabled: true
},
bot_user: {
display_name: "Infisical",
always_online: true
}
},
oauth_config: {
redirect_urls: [`${appCfg.SITE_URL}/api/v1/workflow-integrations/slack/oauth_redirect`],
scopes: {
bot: ["chat:write.public", "chat:write", "channels:read", "groups:read", "im:read", "mpim:read"]
}
},
settings: {
org_deploy_enabled: false,
socket_mode_enabled: false,
token_rotation_enabled: false
}
};
};
import { SlackTriggerFeature, TSlackNotification } from "./slack-types";
export const fetchSlackChannels = async (botKey: string) => {
const slackChannels: {
@@ -80,23 +41,98 @@ export const fetchSlackChannels = async (botKey: string) => {
return slackChannels;
};
const buildSlackPayload = (notification: TSlackNotification) => {
const appCfg = getConfig();
switch (notification.type) {
case SlackTriggerFeature.SECRET_APPROVAL: {
const { payload } = notification;
const messageBody = `A secret approval request has been opened by ${payload.userEmail}.
*Environment*: ${payload.environment}
*Secret path*: ${payload.secretPath || "/"}
View the complete details <${appCfg.SITE_URL}/project/${payload.projectId}/approval?requestId=${
payload.requestId
}|here>.`;
const payloadBlocks = [
{
type: "header",
text: {
type: "plain_text",
text: "Secret approval request",
emoji: true
}
},
{
type: "section",
text: {
type: "mrkdwn",
text: messageBody
}
}
];
return {
payloadMessage: messageBody,
payloadBlocks
};
}
case SlackTriggerFeature.ACCESS_REQUEST: {
const { payload } = notification;
const messageBody = `${payload.requesterFullName} (${payload.requesterEmail}) has requested ${
payload.isTemporary ? "temporary" : "permanent"
} access to ${payload.secretPath} in the ${payload.environment} environment of ${payload.projectName}.
The following permissions are requested: ${payload.permissions.join(", ")}
View the request and approve or deny it <${payload.approvalUrl}|here>.`;
const payloadBlocks = [
{
type: "header",
text: {
type: "plain_text",
text: "New access approval request pending for review",
emoji: true
}
},
{
type: "section",
text: {
type: "mrkdwn",
text: messageBody
}
}
];
return {
payloadMessage: messageBody,
payloadBlocks
};
}
default: {
throw new BadRequestError({
message: "Slack notification type not supported."
});
}
}
};
export const triggerSlackNotification = async ({
projectId,
payloadBlocks,
payloadMessage,
notification,
projectSlackConfigDAL,
projectDAL,
kmsService,
feature
kmsService
}: {
projectId: string;
payloadBlocks: Block[];
payloadMessage: string;
notification: TSlackNotification;
projectSlackConfigDAL: Pick<TProjectSlackConfigDALFactory, "getIntegrationDetailsByProject">;
projectDAL: Pick<TProjectDALFactory, "findById">;
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
feature: SlackTriggerFeature;
}) => {
const { payloadMessage, payloadBlocks } = buildSlackPayload(notification);
const project = await projectDAL.findById(projectId);
const slackIntegration = await projectSlackConfigDAL.getIntegrationDetailsByProject(project.id);
@@ -105,12 +141,12 @@ export const triggerSlackNotification = async ({
}
let targetChannelIds: string[] = [];
if (feature === SlackTriggerFeature.ACCESS_REQUEST) {
if (notification.type === SlackTriggerFeature.ACCESS_REQUEST) {
targetChannelIds = slackIntegration.accessRequestChannels?.split(", ") || [];
if (!targetChannelIds.length || !slackIntegration.isAccessRequestNotificationEnabled) {
return;
}
} else if (feature === SlackTriggerFeature.SECRET_APPROVAL) {
} else if (notification.type === SlackTriggerFeature.SECRET_APPROVAL) {
targetChannelIds = slackIntegration.secretRequestChannels?.split(", ") || [];
if (!targetChannelIds.length || !slackIntegration.isSecretRequestNotificationEnabled) {
return;
@@ -136,6 +172,6 @@ export const triggerSlackNotification = async ({
text: payloadMessage,
blocks: payloadBlocks
})
.catch((err) => void logger.error(err));
.catch((err) => logger.error(err));
}
};
+1 -1
View File
@@ -158,7 +158,7 @@ export const slackServiceFactory = ({
message: `Invalid Slack configuration. ${
appCfg.isCloud
? "Please contact the Infisical team."
: "Contact your instance admin to setup Slack integration in the Admin settings."
: "Contact your instance admin to setup Slack integration in the Admin settings. Your configuration is missing Slack client ID and secret."
}`
});
}
+25
View File
@@ -52,3 +52,28 @@ export enum SlackTriggerFeature {
SECRET_APPROVAL = "secret-approval",
ACCESS_REQUEST = "access-request"
}
export type TSlackNotification =
| {
type: SlackTriggerFeature.SECRET_APPROVAL;
payload: {
userEmail: string;
environment: string;
secretPath: string;
requestId: string;
projectId: string;
};
}
| {
type: SlackTriggerFeature.ACCESS_REQUEST;
payload: {
requesterFullName: string;
requesterEmail: string;
isTemporary: boolean;
secretPath: string;
environment: string;
projectName: string;
permissions: string[];
approvalUrl: string;
};
};
@@ -12,7 +12,6 @@ import { TAuthLoginFactory } from "../auth/auth-login-service";
import { AuthMethod } from "../auth/auth-type";
import { TKmsServiceFactory } from "../kms/kms-service";
import { TOrgServiceFactory } from "../org/org-service";
import { getCustomSlackBotManifest } from "../slack/slack-fns";
import { TUserDALFactory } from "../user/user-dal";
import { TSuperAdminDALFactory } from "./super-admin-dal";
import { LoginMethod, TAdminGetUsersDTO, TAdminSignUpDTO } from "./super-admin-types";
@@ -90,9 +89,7 @@ export const superAdminServiceFactory = ({
data: TSuperAdminUpdate & { slackClientId?: string; slackClientSecret?: string },
userId: string
) => {
const updatedData = {
...data
};
const updatedData = data;
if (data.enabledLoginMethods) {
const superAdminUser = await userDAL.findById(userId);
@@ -263,12 +260,6 @@ export const superAdminServiceFactory = ({
return user;
};
const getCustomSlackBotCreationUrl = async () => {
return `https://api.slack.com/apps?new_app=1&manifest_json=${encodeURIComponent(
JSON.stringify(getCustomSlackBotManifest())
)}`;
};
const getAdminSlackConfig = async () => {
const serverCfg = await serverCfgDAL.findById(ADMIN_CONFIG_DB_UUID);
@@ -301,7 +292,6 @@ export const superAdminServiceFactory = ({
adminSignUp,
getUsers,
deleteUser,
getCustomSlackBotCreationUrl,
getAdminSlackConfig
};
};