mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 14:27:23 +00:00
misc: addressed review comments
This commit is contained in:
@@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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."
|
||||
}`
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user