mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-18 19:39:25 +00:00
feat(slack-integration): add support for secret sync error notifications and enhance notification handling
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
import { validateMicrosoftTeamsChannelsSchema } from "@app/services/microsoft-teams/microsoft-teams-fns";
|
||||
import { TMicrosoftTeamsServiceFactory } from "@app/services/microsoft-teams/microsoft-teams-service";
|
||||
import {
|
||||
TProjectMicrosoftTeamsConfigDALFactory,
|
||||
TProjectMicrosoftTeamsConfigWithIntegrations
|
||||
} from "@app/services/microsoft-teams/project-microsoft-teams-config-dal";
|
||||
|
||||
import { logger } from "../../logger";
|
||||
import { TNotification, TriggerFeature } from "../types";
|
||||
|
||||
const handleMicrosoftTeamsNotification = async ({
|
||||
microsoftTeamsConfig,
|
||||
notification,
|
||||
orgId,
|
||||
microsoftTeamsService
|
||||
}: {
|
||||
microsoftTeamsConfig: TProjectMicrosoftTeamsConfigWithIntegrations;
|
||||
notification: TNotification;
|
||||
orgId: string;
|
||||
microsoftTeamsService: Pick<TMicrosoftTeamsServiceFactory, "sendNotification">;
|
||||
}): Promise<void> => {
|
||||
let targetChannels: unknown;
|
||||
let isEnabled = false;
|
||||
|
||||
switch (notification.type) {
|
||||
case TriggerFeature.ACCESS_REQUEST:
|
||||
case TriggerFeature.ACCESS_REQUEST_UPDATED:
|
||||
targetChannels = microsoftTeamsConfig.accessRequestChannels;
|
||||
isEnabled = microsoftTeamsConfig.isAccessRequestNotificationEnabled;
|
||||
break;
|
||||
case TriggerFeature.SECRET_APPROVAL:
|
||||
targetChannels = microsoftTeamsConfig.secretRequestChannels;
|
||||
isEnabled = microsoftTeamsConfig.isSecretRequestNotificationEnabled;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEnabled && targetChannels) {
|
||||
const { success, data, error: validationError } = validateMicrosoftTeamsChannelsSchema.safeParse(targetChannels);
|
||||
|
||||
if (!success) {
|
||||
logger.error(validationError, "Invalid Microsoft Teams channel configuration");
|
||||
return;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
await microsoftTeamsService
|
||||
.sendNotification({
|
||||
notification,
|
||||
target: data,
|
||||
tenantId: microsoftTeamsConfig.tenantId,
|
||||
microsoftTeamsIntegrationId: microsoftTeamsConfig.id,
|
||||
orgId
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(
|
||||
error,
|
||||
`Error sending Microsoft Teams notification. Notification type: ${notification.type}, Tenant ID: ${microsoftTeamsConfig.tenantId}, Project ID: ${microsoftTeamsConfig.projectId}`
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const triggerMicrosoftTeamsNotification = async ({
|
||||
projectId,
|
||||
notification,
|
||||
orgId,
|
||||
projectMicrosoftTeamsConfigDAL,
|
||||
microsoftTeamsService
|
||||
}: {
|
||||
projectId: string;
|
||||
notification: TNotification;
|
||||
orgId: string;
|
||||
projectMicrosoftTeamsConfigDAL: Pick<TProjectMicrosoftTeamsConfigDALFactory, "getIntegrationDetailsByProject">;
|
||||
microsoftTeamsService: Pick<TMicrosoftTeamsServiceFactory, "sendNotification">;
|
||||
}): Promise<void> => {
|
||||
try {
|
||||
const config = await projectMicrosoftTeamsConfigDAL.getIntegrationDetailsByProject(projectId);
|
||||
if (config) {
|
||||
await handleMicrosoftTeamsNotification({
|
||||
microsoftTeamsConfig: config,
|
||||
notification,
|
||||
orgId,
|
||||
microsoftTeamsService
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(error, `Error handling Microsoft Teams notification. Project ID: ${projectId}`);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
import {
|
||||
TProjectSlackConfigDALFactory,
|
||||
TProjectSlackConfigWithIntegrations
|
||||
} from "@app/services/slack/project-slack-config-dal";
|
||||
import { sendSlackNotification } from "@app/services/slack/slack-fns";
|
||||
|
||||
import { logger } from "../../logger";
|
||||
import { TNotification, TriggerFeature } from "../types";
|
||||
|
||||
const handleSlackNotification = async ({
|
||||
slackConfig,
|
||||
notification,
|
||||
orgId,
|
||||
kmsService
|
||||
}: {
|
||||
slackConfig: TProjectSlackConfigWithIntegrations;
|
||||
notification: TNotification;
|
||||
orgId: string;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
}): Promise<void> => {
|
||||
let targetChannelIds: string[] = [];
|
||||
let isEnabled = false;
|
||||
|
||||
switch (notification.type) {
|
||||
case TriggerFeature.ACCESS_REQUEST:
|
||||
case TriggerFeature.ACCESS_REQUEST_UPDATED:
|
||||
targetChannelIds = slackConfig.accessRequestChannels?.split(", ") || [];
|
||||
isEnabled = slackConfig.isAccessRequestNotificationEnabled;
|
||||
break;
|
||||
case TriggerFeature.SECRET_APPROVAL:
|
||||
targetChannelIds = slackConfig.secretRequestChannels?.split(", ") || [];
|
||||
isEnabled = slackConfig.isSecretRequestNotificationEnabled;
|
||||
break;
|
||||
case TriggerFeature.SECRET_SYNC_ERROR:
|
||||
targetChannelIds = slackConfig.secretSyncErrorChannels?.split(", ") || [];
|
||||
isEnabled = slackConfig.isSecretSyncErrorNotificationEnabled;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetChannelIds.length && isEnabled) {
|
||||
await sendSlackNotification({
|
||||
orgId,
|
||||
notification,
|
||||
kmsService,
|
||||
targetChannelIds,
|
||||
slackIntegration: slackConfig
|
||||
}).catch((error) => {
|
||||
logger.error(
|
||||
error,
|
||||
`Error sending Slack notification. Notification type: ${notification.type}, Target channel IDs: ${targetChannelIds.join(", ")}, Project ID: ${slackConfig.projectId}`
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const triggerSlackNotification = async ({
|
||||
projectId,
|
||||
notification,
|
||||
orgId,
|
||||
projectSlackConfigDAL,
|
||||
kmsService
|
||||
}: {
|
||||
projectId: string;
|
||||
notification: TNotification;
|
||||
orgId: string;
|
||||
projectSlackConfigDAL: Pick<TProjectSlackConfigDALFactory, "getIntegrationDetailsByProject">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
}): Promise<void> => {
|
||||
try {
|
||||
const config = await projectSlackConfigDAL.getIntegrationDetailsByProject(projectId);
|
||||
if (config) {
|
||||
await handleSlackNotification({ slackConfig: config, notification, orgId, kmsService });
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(error, `Error handling Slack notification. Project ID: ${projectId}`);
|
||||
}
|
||||
};
|
||||
@@ -1,8 +1,7 @@
|
||||
import { validateMicrosoftTeamsChannelsSchema } from "@app/services/microsoft-teams/microsoft-teams-fns";
|
||||
import { sendSlackNotification } from "@app/services/slack/slack-fns";
|
||||
|
||||
import { logger } from "../logger";
|
||||
import { TriggerFeature, TTriggerWorkflowNotificationDTO } from "./types";
|
||||
import { triggerMicrosoftTeamsNotification } from "./notification-handlers/microsoft-teams";
|
||||
import { triggerSlackNotification } from "./notification-handlers/slack";
|
||||
import { TTriggerWorkflowNotificationDTO } from "./types";
|
||||
|
||||
export const triggerWorkflowIntegrationNotification = async (dto: TTriggerWorkflowNotificationDTO) => {
|
||||
try {
|
||||
@@ -16,88 +15,25 @@ export const triggerWorkflowIntegrationNotification = async (dto: TTriggerWorkfl
|
||||
return;
|
||||
}
|
||||
|
||||
const microsoftTeamsConfig = await projectMicrosoftTeamsConfigDAL.getIntegrationDetailsByProject(projectId);
|
||||
const slackConfig = await projectSlackConfigDAL.getIntegrationDetailsByProject(projectId);
|
||||
const handlerPromises = [
|
||||
triggerSlackNotification({
|
||||
projectId,
|
||||
notification,
|
||||
orgId: project.orgId,
|
||||
projectSlackConfigDAL,
|
||||
kmsService
|
||||
}),
|
||||
|
||||
if (slackConfig) {
|
||||
if (
|
||||
notification.type === TriggerFeature.ACCESS_REQUEST ||
|
||||
notification.type === TriggerFeature.ACCESS_REQUEST_UPDATED
|
||||
) {
|
||||
const targetChannelIds = slackConfig.accessRequestChannels?.split(", ") || [];
|
||||
if (targetChannelIds.length && slackConfig.isAccessRequestNotificationEnabled) {
|
||||
await sendSlackNotification({
|
||||
orgId: project.orgId,
|
||||
notification,
|
||||
kmsService,
|
||||
targetChannelIds,
|
||||
slackIntegration: slackConfig
|
||||
}).catch((error) => {
|
||||
logger.error(error, "Error sending Slack notification");
|
||||
});
|
||||
}
|
||||
} else if (notification.type === TriggerFeature.SECRET_APPROVAL) {
|
||||
const targetChannelIds = slackConfig.secretRequestChannels?.split(", ") || [];
|
||||
if (targetChannelIds.length && slackConfig.isSecretRequestNotificationEnabled) {
|
||||
await sendSlackNotification({
|
||||
orgId: project.orgId,
|
||||
notification,
|
||||
kmsService,
|
||||
targetChannelIds,
|
||||
slackIntegration: slackConfig
|
||||
}).catch((error) => {
|
||||
logger.error(error, "Error sending Slack notification");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
triggerMicrosoftTeamsNotification({
|
||||
projectId,
|
||||
notification,
|
||||
orgId: project.orgId,
|
||||
projectMicrosoftTeamsConfigDAL,
|
||||
microsoftTeamsService
|
||||
})
|
||||
];
|
||||
|
||||
if (microsoftTeamsConfig) {
|
||||
if (
|
||||
notification.type === TriggerFeature.ACCESS_REQUEST ||
|
||||
notification.type === TriggerFeature.ACCESS_REQUEST_UPDATED
|
||||
) {
|
||||
if (microsoftTeamsConfig.isAccessRequestNotificationEnabled && microsoftTeamsConfig.accessRequestChannels) {
|
||||
const { success, data } = validateMicrosoftTeamsChannelsSchema.safeParse(
|
||||
microsoftTeamsConfig.accessRequestChannels
|
||||
);
|
||||
|
||||
if (success && data) {
|
||||
await microsoftTeamsService
|
||||
.sendNotification({
|
||||
notification,
|
||||
target: data,
|
||||
tenantId: microsoftTeamsConfig.tenantId,
|
||||
microsoftTeamsIntegrationId: microsoftTeamsConfig.id,
|
||||
orgId: project.orgId
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(error, "Error sending Microsoft Teams notification");
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (notification.type === TriggerFeature.SECRET_APPROVAL) {
|
||||
if (microsoftTeamsConfig.isSecretRequestNotificationEnabled && microsoftTeamsConfig.secretRequestChannels) {
|
||||
const { success, data } = validateMicrosoftTeamsChannelsSchema.safeParse(
|
||||
microsoftTeamsConfig.secretRequestChannels
|
||||
);
|
||||
|
||||
if (success && data) {
|
||||
await microsoftTeamsService
|
||||
.sendNotification({
|
||||
notification,
|
||||
target: data,
|
||||
tenantId: microsoftTeamsConfig.tenantId,
|
||||
microsoftTeamsIntegrationId: microsoftTeamsConfig.id,
|
||||
orgId: project.orgId
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error(error, "Error sending Microsoft Teams notification");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await Promise.allSettled(handlerPromises);
|
||||
} catch (error) {
|
||||
logger.error(error, "Error triggering workflow integration notification");
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ import { TProjectSlackConfigDALFactory } from "@app/services/slack/project-slack
|
||||
export enum TriggerFeature {
|
||||
SECRET_APPROVAL = "secret-approval",
|
||||
ACCESS_REQUEST = "access-request",
|
||||
ACCESS_REQUEST_UPDATED = "access-request-updated"
|
||||
ACCESS_REQUEST_UPDATED = "access-request-updated",
|
||||
SECRET_SYNC_ERROR = "secret-sync-error"
|
||||
}
|
||||
|
||||
export type TNotification =
|
||||
@@ -51,6 +52,16 @@ export type TNotification =
|
||||
editorFullName?: string;
|
||||
editorEmail?: string;
|
||||
};
|
||||
}
|
||||
| {
|
||||
type: TriggerFeature.SECRET_SYNC_ERROR;
|
||||
payload: {
|
||||
syncName: string;
|
||||
syncActionLabel: string;
|
||||
syncDestination: string;
|
||||
failureMessage: string;
|
||||
syncUrl: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type TTriggerWorkflowNotificationDTO = {
|
||||
|
||||
Reference in New Issue
Block a user